繁体   English   中英

如何允许 SignalR 使用 EF6 将更新从 DB 推送到浏览器

[英]How to allow SignalR to push updates from DB to the browser using EF6

如何允许SignalR使用EF6将更新从SQLServer DB推送到浏览器。

这是我的操作方法:

public ActionResult Index()
        {
            var currentGates = _ctx.Transactions
                                                .GroupBy(item => item.SubGateId)
                                                .SelectMany(group => group.OrderByDescending(x => x.TransactionDateTime)
                                                .Take(1))
                                                .Include(g => g.Card)
                                                .Include(g => g.Student)
                                                .Include(g => g.Student.Faculty)
                                                 .Include(g => g.Student.Department)
                                                .Include(g => g.SubGate)
                                                .ToList();


            return View(currentGates);
        }

经过大量搜索,我得到的唯一结果是:

ASP.NET MVC 5 SignalR,SqlDependency 和 EntityFramework 6

我已经尝试了建议的方法,但它没有用,除此之外,我还发现了一个非常重要的安全问题,即在隐藏字段中存储敏感数据!

我的问题是:

如何根据事务表上的任何Insert更新我的视图?

所以基本上你需要做的是覆盖SaveChanges()方法和操作 SignalR function:

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
  {
  public override int SaveChanges()
        {
            var entities = ChangeTracker.Entries().Where(x => x.Entity is Transactions && x.State == EntityState.Added) ;
            IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
            foreach (var entity in entities)
            {
              hubContext.Clients.All.notifyClients(entity);
            }

            return base.SaveChanges();
         }
    }

通常我会插入创建事务的服务或保存更改事件,如@Vince Suggested 但是因为您的新要求

问题是:我无法控制将学生事务推送到数据库的 sdk,所以我希望有一些方法可以直接在数据库表上工作。

在您的情况下,您可以使用 SQL 来查看表格

注意:小心使用SqlDependency class - 它存在memory 泄漏问题。

using(var tableDependency = new SqlTableDependency<Transaction>(conString))
{
    tableDependency.OnChanged += TableDependency_Changed;
    tableDependency.Start();
}

void TableDependency_Changed(object sender, RecordChangedEventArgs<Transaction> e)
{
    if (e.ChangeType != ChangeType.None)
    {
        var changedEntity = e.Entity;
        //You'll need to change this logic to send only to the people you want to 
        IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<MyHub>();
        hubContext.Clients.All.notifyClients(entity);
    }
}

编辑似乎您可能有其他依赖项,例如包含您想要的结果。 因此,您可以做的是从实体中解析 Id,然后使用 EntityFramework 调用 Get。

if (e.ChangeType != ChangeType.None)
{
    var changedEntity = e.Entity;
    var id = GetPrimaryKey(changedEntity)
    _ctx.Transactions.Find(id);
}

编辑其他方法的方法。

  1. 如果您的实体有最后更新的字段,您可以在计时器上扫描表的更改。 客户端有一个计时器,它在最后一次检查更改时发送。 服务器获取最后更新时间戳大于传入时间的所有实体

  2. 尽管您无权访问 EF,但您可能有权访问 web api 请求。 每当有人调用更新或创建方法时,只需获取已更改实体的 id,将所有已更改实体的 id 弹出到后台服务,该服务将发送 signalr 通知,

现在唯一的问题是获取主键,这可以通过手动将类型映射到它们的 id 属性来完成,或者可以使用 model 中的元数据来完成,但这有点复杂

请注意,您可能可以修改它,以便它在所有表上通用

我了解您有以下数据流:

  • 6x 读卡器设备
  • “经理”接收读卡器数据并将其推送到
  • SQLServer“事务”表

所有这些都是第 3 方。 您的目标是拥有一个自定义 ASP.Net web 页面,该页面显示读卡器收到的最新记录:

所以问题基本上是,您的 ASP.net 服务需要被通知受监控数据库表中的更改。

快速而肮脏的方法:

  1. 在你的大“事务”表上实现一个数据库触发器,更新一个轻量级“状态”表
  2. CREATE TABLE state( GateId INT NOT NULL, UserName VARCHAR (20) NOT NULL, PRIMARY KEY (GateId)); 此表旨在每个门只有 1 条记录。 6 个门 -> 这张表中有 6 条记录。
  3. 更改您的 ASP.net 服务以以例如 200 毫秒的间隔轮询“状态”表。 进行此类 hack 时,请确保您正在轮询的表没有太多记录,一旦您检测到更改。 通知您的 SignalR 客户。

恕我直言,通过数据库的数据流是一个糟糕的设计决策(或限制)。 如果您的“经理”不仅将数据推送到数据库,而且随后通知所有 SignalR 客户端,那就更好了。 这个数据流基本上是@Vince 回答所假设的。

编辑:由于您已经发布了您正在使用的实际设备,我鼓励您仔细检查是否可以直接连接到读卡器。 一旦设备读取了学生卡,就有办法注册某种回调。 这样做的唯一目标是实现这样的严格数据流/架构:

  -> connect 6x card readers to your 
  -> ASP.Net service which at a single point in your code:
        -> updates the database
        -> updates the Signal R clients

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM