我正在尝试在单核Windows Server 2012主机上托管ASP.NET Core MVC项目。我正在使用ASP.NET Core MVC 1.0.0并在带有.NET Framework 4.6.1的IIS 8上运行该应用程序在第一个~10分钟正常工作,然后突然服务器停止响应。
起初我以为它在数据库端是死锁所以我在DbContext类中添加了日志记录:
private static long ActiveContextCount = 0;
private ILogger _log;
private Stopwatch _timer = new Stopwatch();
private Guid _contextId = Guid.NewGuid();
public BlogContext(string nameOrConnectionString, ILoggerFactory logger)
:base(nameOrConnectionString)
{
_log = logger.CreateLogger<BlogContext>();
Database.Log = l =>
{
_log.LogInformation(l);
};
ActiveContextCount++;
_timer.Start();
_log.LogInformation("BlogContext created. GUID:{0}, Active count {1}", _contextId, ActiveContextCount);
}
protected override void Dispose(bool disposing)
{
ActiveContextCount--;
_timer.Stop();
_log?.LogInformation("BlogContext Disposed. GUID:{0}, Live time: {1}ms, Active count {2}", _contextId, _timer.ElapsedMilliseconds, ActiveContextCount);
base.Dispose(disposing);
}
我正在使用Entity Framework 6,我已将DbContext设置为作用域:
services.AddScoped(p => new BlogContext(_dataDbConnectionString, p.GetRequiredService<ILoggerFactory>()));
事实证明,数据库操作一切正常。我在日志中跟踪请求,并注意到某些请求的最后一个日志为:
[Information] Executing ViewResult, running view at path "/Views/Blog/Details.cshtml".
永远不会完成(即无法在日志中找到处理)。从那时起,ActiveContextCount
只会累积到几百个,整个应用程序会挂起并停止响应。
(编辑08/29)另一个例子,甚至没有执行任何查询:
[Information] Request starting HTTP/1.1 GET http://myapp/
[Information] UsersContext created. GUID:bb7743b9-7999-4a01-819f-3d239d34d4d9, Active count 7
[Information] HttpContext.User merged via AutomaticAuthentication from authenticationScheme: "Identity.Application".
[Information] BlogContext created. GUID:8c7505d4-5c87-428e-ad56-12f35f54aadc, Active count 6
[Information] Executing action method "MyApp.Controllers.HomeController.Index (MyApp)" with arguments (["1"]) - ModelState is Valid
[Information] Executing ViewResult, running view at path "/Views/Home/Index.cshtml".
我在这一点上陷入困境。为什么视图结果永远不会完成?这是框架或我的应用程序中的错误吗?即使有错误,为什么请求只是在一些超时后被中止并放弃?我试图在web.config中指定超时但没有帮助:
<aspNetCore processPath=".\MyApp.exe" arguments="" forwardWindowsAuthToken="false" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" requestTimeout="00:00:40" />
如何进一步调试此问题?
答案 0 :(得分:4)
经过几周的调试后,我终于找到了问题所在。这个问题确实存在。我浏览了asp.net core doc并注意到这一行:
PartialAsync方法适用于包含异步代码的部分视图(尽管通常不鼓励使用视图中的代码)。
然后我去查看github上Html.Partial
的实际实施情况。
var result = htmlHelper.RenderPartialAsync(partialViewName, htmlHelper.ViewData.Model, viewData);
result.GetAwaiter().GetResult();
因此,同步部分实际上只是异步版本的阻塞包装器!这是经典的异步等待死锁(1),因为我在局部视图中调用@await Component.InvokeAysnc
(因为没有用于调用View组件的同步版本)。我已将所有Html.Partial
引用替换为await Html.PartialAsync
,问题已解决。我真的希望他们可以对此有更好的警告...... :(
P.S。我没有发布超过2个链接的声誉,但为什么......
(1):blog.stephencleary.com/2012/07/dont-block-on-async-code.html