【问题标题】:ASP.Net MVC 4 controller hangs whenever async is used每当使用异步时,ASP.Net MVC 4 控制器就会挂起
【发布时间】:2012-07-06 14:34:37
【问题描述】:

我正在使用带有 .Net 4.5 和 ASP MVC 4 RC 的 Visual Studio 2012 RC。每当我使用异步时,它都会挂起。控制器操作方法使用异步,但本身不是异步控制器方法。

没有记录错误或抛出异常,但浏览器永远显示“Waiting for www.myweb.local”。

// Simplest possible async
public class Waiter
{
    public async Task<int> GetValue()
    {
        await Task.Yield();
        return await Task.Factory.StartNew(() => 42);
    }
}

// simplest possible controller that uses the async
public class HomeController : Controller

    public ActionResult Index()
    {
        var waiter = new Waiter();
        var resultTask = waiter.GetValue();
        int result = resultTask.Result;

        // it never gets here 
        return View();
    }
}

我已经完成了in this answer 中提到的事情,但它仍然不起作用。 IE。 web.config 包含

<add key="aspnet:UseTaskFriendlySynchronizationContext" value="true"/>

而神奇的词await Task.Yield();在异步方法中。

.Net 框架版本是 4.5.50501。我在 IIS Express 和 IIS 6.0 上观察到了这种行为。

我尝试将“2012 年 7 月更新”应用到 VS2012,但这并没有解决问题。

This answer suggests 这可能是因为当我等待它时任务已经完成,但是如果是这样的话,这应该有效,但它没有:

public class Waiter
{
    public async Task<int> GetValue()
    {
        await Task.Yield();
        return await Task.Factory.StartNew(() => 
            {
                Thread.Sleep(1500);
                return 42;
            });
    }
}

有几个人建议需要ConfigureAwait(false),但此代码也不起作用:

    public async Task<int> GetValue()
    {
        var task = new Task<int>(() => 42);
        return await task.ConfigureAwait(false);
    }

以下确实适用于剃刀视图引擎,但不适用于 spark。当然应该有办法让其他场景也能正常工作?不能在同步代码中使用异步任务吗?

public class Waiter
{
    public async Task<int> GetValue()
    {
        return await Task.Factory.StartNew(() => 42);
    }
}

public class HomeController : Controller
{
    public async Task<ActionResult> IndexAsync()
    {
        await Task.Yield();
        var waiter = new Waiter();
        int result = await waiter.GetValue();

        return View();
    }
}

我知道这是不是发布的软件,但微软的 RC 通常很稳定,所以我很惊讶它失败了,而且失败的方式毫无帮助。

【问题讨论】:

  • 对不起,如果我遗漏了什么,但为什么通过访问 Result 属性而不是将其标记为异步并在那里使用 await 来阻止索引?如果这是有意为之,您可能需要使用 ConfigureAwait(false) 以便继续不会安排回同一个线程。
  • 我正在测试将现有网站移植到 .Net 4.5。它使用火花视图引擎。我想在处理异步控制器之前让异步工作,以及 spark 是否可以处理 Task (我最初的印象是没有)。但不管我能不能做到这一点,这种情况应该可行。
  • 为什么要从 AsyncController 派生?那没有必要。查看我的异步示例asp.net/mvc/tutorials/mvc-4/…
  • 感谢 Rick 的提示,我已经修改了代码,例如适合。

标签: c# asp.net-mvc task-parallel-library async-await


【解决方案1】:

你正在造成死锁,just like this question

James Manning 的建议是正确的,但你必须await ConfigureAwait 的结果,像这样:

public async Task<int> GetValue()
{
    var task = new Task<int> (() => 42);
    return await task.ConfigureAwait(false);
}

一般来说,混合同步和异步代码是一个非常糟糕的主意,除非您真的知道自己在做什么。使控制器动作异步会好得多。

【讨论】:

  • 我同意 - 特别是现在使控制器方法异步变得如此容易。虽然我可以看到一些(非常 非常 罕见)在同步处理程序中并行运行某些任务可能有意义的情况。在被异步控制器迷住之前,总是值得一读这篇文章:blog.stevensanderson.com/2010/01/25/…
  • 肯定有任何使用 async 关键字“混合同步和异步代码”的 c# 程序吗?使用异步控制器只是意味着边界在框架中。
  • 关于“现在让控制器方法异步变得如此容易” - 如果您有很多使用 spark 视图引擎的现有视图,则不会。
  • @Anthony:我所说的“混合”是指每个应用程序都有一个事件控制器(UI 应用程序有一个消息泵;ASP.NET 应用程序有一个请求上下文)。将async 一直延伸到该事件控制器是最简洁和最简单的设计。您不想在将同步事件处理程序调用到async 层的意义上“混合”。
  • 我没用过spark,但如果只是一个视图引擎,你就不能让你的控制器方法async反正?
【解决方案2】:

我在测试版中的异步工作很好。我没有测试过,但我猜这是因为你的控制器方法不是异步的。改成这样:

public async Task<ActionResult> IndexAsync()
{
    var waiter = new Waiter();
    int result = await waiter.GetValue();

    // it never gets here 
    return View();
}

【讨论】:

  • 如果是“因为控制器方法不是异步的”,你是说使用异步任务永远不会在同步代码中工作吗?否则,应该有办法让这段代码正常工作。
  • 那么 GetValue() 没有完成......我想不出一个明显的原因,从你所拥有的,我现在在火车上!如果没有人打败我,我稍后会看看。
  • 如果你在等待之后访问结果(用它做某事)会发生什么?
猜你喜欢
  • 1970-01-01
  • 2012-07-05
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
相关资源
最近更新 更多