【问题标题】:Why does MVC 4 dispose the controller when action await something?为什么 MVC 4 在等待动作时处理控制器?
【发布时间】:2013-03-11 19:35:31
【问题描述】:

为什么我的控制器在await 语句之后被释放?

    public async Task<ViewResult> MyAction()
    {
            await Task.Yield();

            // controller disposed at this point... why?

            return this.View();
    }

我的控制器使用它通过覆盖Dispose 方法释放的资源...但使用 async/await 似乎打破了这一点,因为它会在执行 await 语句后立即释放控制器...我该如何释放以支持 async/await 的方式获取资源?

编辑: dispose 方法的调用堆栈中的最后一个方法:

MyWebRole.dll!MyWebRole.Code.MyController.Dispose(bool disposing = true) Line 102   C#
System.Web.Mvc.dll!System.Web.Mvc.Controller.Dispose() + 0x25 bytes   
System.Web.Mvc.dll!System.Web.Mvc.DefaultControllerFactory.ReleaseController(System.Web.Mvc.IController controller = {MyWebRole.Areas.App.Controllers.LongPollingController}) + 0x3e bytes   
System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.BeginProcessRequest.AnonymousMethod__5() + 0x70 bytes   
System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.MakeVoidDelegate.AnonymousMethod__0() + 0x2d bytes   
System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.BeginSynchronous<System.Web.Mvc.Async.AsyncVoid>.AnonymousMethod__7(System.IAsyncResult _ = {System.Web.Mvc.Async.SimpleAsyncResult}) + 0x2b bytes   
System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.Web.Mvc.Async.AsyncVoid>.End() + 0x99 bytes   
System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.End<System.Web.Mvc.Async.AsyncVoid>(System.IAsyncResult asyncResult = {System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.Web.Mvc.Async.AsyncVoid>}, object tag = {object}) + 0x3c bytes   
System.Web.Mvc.dll!System.Web.Mvc.Async.AsyncResultWrapper.End(System.IAsyncResult asyncResult = {System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.Web.Mvc.Async.AsyncVoid>}, object tag = {object}) + 0x29 bytes   
System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.EndProcessRequest.AnonymousMethod__d() + 0x27 bytes   
System.Web.Mvc.dll!System.Web.Mvc.SecurityUtil.GetCallInAppTrustThunk.AnonymousMethod__0(System.Action f = {Method = {System.Reflection.RuntimeMethodInfo}}) + 0x20 bytes   
System.Web.Mvc.dll!System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust(System.Action action = {Method = {System.Reflection.RuntimeMethodInfo}}) + 0x3e bytes   
System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.EndProcessRequest(System.IAsyncResult asyncResult = {System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.Web.Mvc.Async.AsyncVoid>}) + 0x77 bytes   
System.Web.Mvc.dll!System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(System.IAsyncResult result = {System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult<System.Web.Mvc.Async.AsyncVoid>}) + 0x27 bytes   

Dispose 方法正在被 disposing = true 调用......这很糟糕。也许是一个错误?

编辑 2:我已经尝试子类化 AsyncController,但同样的情况发生了。

有什么解决办法吗?

【问题讨论】:

  • await 语句后是否保留了对控制器的引用?
  • 只有this本身...它在await之前和之后是同一个对象。
  • 它是一样的......但是被丢弃了。
  • 是否有另一个线程在对象上调用 dispose?你试过在 dispose 函数上设置断点,看看是谁在调用它吗?
  • 已编辑问题以包含 dispose 方法的调用堆栈...调用它的是 MVC。

标签: c# asp.net-mvc-4 .net-4.5 async-await c#-5.0


【解决方案1】:

根据堆栈跟踪,似乎任何启动进程请求都决定它结束它,因此您丢失了对控制器的引用,并且它有资格进行垃圾收集/处理。我会调查是什么启动了流程请求以及为什么会结束它。

【讨论】:

  • 事实并非如此......它是 MVC 4 故意处理我的控制器,而不是垃圾收集器,但我不知道为什么,因为操作是 async。另外,代码的代码执行在await之后正常继续,我可以看到它是活着的,但是被释放了。
【解决方案2】:

问题中显示的调用堆栈来自 MVC3 而不是 MVC4。不幸的是,MVC3 不支持基于Task 的异步调用。当您调用 await 时,任务可能会很好地启动,但 MVC3 对此一无所知,因此它只是在其上调用 ToString() 并将其作为 ContentResult 返回。

在 MVC4 中添加了基于 Task 的异步支持,实际上甚至不需要从 AsyncController 派生。 MVC4 中的所有Controllers 都支持同步,以及基于Task 的异步。如果您使用 Async/Completed 模式,则只需要 AsyncController

【讨论】:

  • 嗯...其实我以为我使用的是 MVC 4,但你说得对,它是 MVC 3,也许有人忘记升级项目了。现在它正在按预期工作。非常感谢!
  • +1 好眼力。我还没有大量使用过任何一个版本的 MVC。堆栈跟踪中的什么告诉您它是 MVC3 而不是 4?
  • @chuex 对 SecurityUtil 的调用不会出现在 MVC4 中。
  • @Eilon - 感谢您的回答。我想知道任何普通人如何根据调用堆栈发现差异。然后我查看了您的个人资料并将 2 和 2 放在一起。
  • @chuex 我实际上询问了团队中的另一位开发人员(编写这部分 MVC 的人),所以完全归功于他! :)
【解决方案3】:

我遇到了这个问题,困扰了我一整天。我终于意识到我在 ControllerFactory 中连接的 ActionInvoker 是从 ControllerActionInvoker 继承的。当我将其更改为 AsyncControllerActionInvoker 时,问题就消失了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-15
    • 2012-12-07
    • 1970-01-01
    • 2023-03-08
    • 1970-01-01
    • 2014-02-27
    相关资源
    最近更新 更多