在我的应用程序中,我通过上传XML文件开始导入过程。上载后,将运行一系列存储过程并解析xml文件,并将数据插入到许多不同的表中。随着它的进展,更新Stats
表以显示插入的进度。 Stats
表有4列:BatchId
,BatchCount
,ProcessCount
和ErrorCount
。 BatchCount
是所有记录的计数。如果正确插入记录而没有问题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实现中。任何帮助表示赞赏!
答案 0 :(得分:3)
最好使用GetHubContext和Timer。
我在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问题。因此,我建议您在集线器外使用GetHubContext
和Timer
。
答案 1 :(得分:2)
你正在做一个实体框架的大诺,你有一个长寿的DbContext。你永远不应该这样做。
在这种情况下,您遇到了Entity Framework的Change Tracker问题。默认情况下,EF使用MergeOption.AppendOnly
。
这意味着默认情况下,在每个EF查询中,EF只会将行反序列化为对象,IFF键与上下文的更改跟踪器中的对象不匹配。
因此,假设您在每个循环中使用相同的EF上下文实例,EF每次执行查询时都会使用缓存的值(SQL运行,但EF不会按预期创建或更改对象)。如果您遵守EF上下文短暂的规则,则完全可以预料到这一点。
要解决此问题,您有几种选择。
MergeOption.OverwriteChanges
。