SignalR轮询并不总是返回准确的数据库结果

时间:2014-04-23 23:48:52

标签: c# linq signalr

在我的应用程序中,我通过上传XML文件开始导入过程。上载后,将运行一系列存储过程并解析xml文件,并将数据插入到许多不同的表中。随着它的进展,更新Stats表以显示插入的进度。 Stats表有4列:BatchIdBatchCountProcessCountErrorCountBatchCount是所有记录的计数。如果正确插入记录而没有问题ProcessCount增加1,如果失败ErrorCount增加1.(这两列在导入过程中总是在变化)

我的主要目标是使用SignalR显示导入进度。我有一个轮询方法,轮询很好,因为我在UI中看到更新的时间戳。然而问题是,计数总是为0(初始值),或非常偶尔会读取一次并显示随机的内容,如985.如果它确实读取了一个值,它只会执行一次并且不会再次更改。这是我的中心方法:

public void BeginPolling()
{
    while (true)
    {
        var stats = _repository.GetImportStats();
        var message = "Preparing file...";

        if (stats != null)
        {
            message = DateTime.Now + " - Count: " + stats.ProcessCount.ToString();
        }
        else
        { 
            message = DateTime.Now + " - Stats result returned null.";
        }

        //the message displays in a div on my UI
        Clients.Caller.showProgress(message);

        //I have tried various sleep times (1000, 5000, 10000)
        Thread.Sleep(5000);
    }
}

下面是我的_repository.GetImportStats方法,出于测试目的,它只是抓取第一个(也是唯一的)记录:

public Stats GetImportStats()
{
    return DataContext.Stats.FirstOrDefault();
}

同样为了测试,我尝试在我的UI上放一个按钮,对同一个GetImportStats()方法进行ajax调用,它总是返回ProcessCount就好了,所以我认为问题在于在我的SignalR实现中。任何帮助表示赞赏!

2 个答案:

答案 0 :(得分:3)

最好使用GetHubContextTimer

我在BeginPolling看到的一个潜在问题是它永远不会返回。对于除WebSockets之外的所有SignalR传输,这意味着每次调用BeginPolling时都会启动永不结束的 XHR。

这不仅会不必要地浪费服务器资源,还可能会影响客户自browsers limit the number of simultaneous connections that can be made to a single server以来接收更多邮件的能力。


P.S。制作BeginPolling async并使用await Task.Delay(...);可以防止您不必要地使用Thread.Sleep保留服务器线程,但这无法解决您永无止境的XHR问题。因此,我建议您在集线器外使用GetHubContextTimer

答案 1 :(得分:2)

你正在做一个实体框架的大诺,你有一个长寿的DbContext。你永远不应该这样做。

在这种情况下,您遇到了Entity Framework的Change Tracker问题。默认情况下,EF使用MergeOption.AppendOnly

这意味着默认情况下,在每个EF查询中,EF只会将行反序列化为对象,IFF键与上下文的更改跟踪器中的对象不匹配。

因此,假设您在每个循环中使用相同的EF上下文实例,EF每次执行查询时都会使用缓存的值(SQL运行,但EF不会按预期创建或更改对象)。如果您遵守EF上下文短暂的规则,则完全可以预料到这一点。

要解决此问题,您有几种选择。

  • 每个循环实例化一个新的EF上下文(并更改跟踪器)。
  • 告诉EF在每个查询中使用MergeOption.OverwriteChanges
  • 告诉EF不要使用更改跟踪器AT ALL(这会禁用写入权限,但要快得多)。
相关问题