如何使ASP.NET MVC控制器方法异步

Gav*_*vin 1 task-parallel-library asp.net-mvc-4

我正在启动多个ajax调用到各种MVC控制器来加载我的页面的不同部分.然而,当它到达控制器时,似乎只有一个一次运行.我猜这是因为默认ASP.Net MVC控制器是同步的?我还测试了在2个浏览器选项卡上加载页面,第二个选项卡总是等待第一个.

为了解决这个问题,我试图使控制器方法异步.我通过执行以下操作完成了此操作

  1. 将Async附加到控制器方法名称
  2. 使控制器方法返回异步任务
  3. 使用Task.Factory.StartNew方法在单独的线程中执行方法中的工作主体.

例如,有问题的控制器方法现在看起来像这样......

    public async Task<JsonResult> GetUser(int userId)
    {
        var result = await Task.Factory.StartNew(() => Task.Run(() =>
        {                
            return userService.GetUser(userId);
        })).Result;
        return new JsonResult()
        {
            Data = result,
            JsonRequestBehavior = JsonRequestBehavior.AllowGet
        };
    } 
Run Code Online (Sandbox Code Playgroud)

但它似乎仍然是同步的.我错过了什么或完全以错误的方式解决这个问题吗?我没有真正使用任务库,所以可能会遗漏一些大的东西?

Eri*_*sch 9

不,你的假设很可能是错误的.您的问题可能是两个问题中的一个(或两个).

首先,大多数Web浏览器都有请求限制,一次只允许对同一服务器发出一定数量的请求.

其次,您可能遇到Session对象的限制,导致使用会话序列化的多个请求,因为Session本身不是多线程的.

http://tech-journals.com/jonow/2011/10/22/the-downsides-of-asp-net-session-state

简短的回答是,如果你不在动作方法中使用session,只需将其添加到方法中......

[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{        
    //...As above
}
Run Code Online (Sandbox Code Playgroud)

如果您只需要阅读会话,请执行以下操作:

[SessionState(SessionStateBehavior.ReadOnly)]
public class AjaxTestController : Controller
{        
    //...As above
}
Run Code Online (Sandbox Code Playgroud)

但是,由于不同的浏览器具有特定的请求限制,因此您无法对浏览器限制做些什么.这些可以通过注册表(或浏览器配置)条目(通常)进行更改,但在大多数情况下,您无法强制用户执行此操作.

  • @Gavin - 顺便说一下,这是XY问题的典型例子.http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem - 您遇到问题,您的请求被序列化,因此您认为问题是因为您没有使用异步..所以你问一下异步而不是问你真正的问题,序列化的控制器方法. (3认同)
  • @Gavin - 那是因为问题与异步无关。异步用于获得更好的资源可扩展性。此问题特定于会话。 (2认同)