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

时间:2014-03-03 08:21:19

标签: asp.net-mvc-4 task-parallel-library

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

为了解决这个问题,我尝试使控制器方法异步。我通过以下方式完成了这个

  1. 将Async附加到控制器方法名称
  2. 使控制器方法返回异步任务
  3. 使用Task.Factory.StartNew方法在单独的线程中执行方法中的工作主体。
  4. 例如,现在所讨论的控制器方法看起来像这样......

        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
            };
        } 
    

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

3 个答案:

答案 0 :(得分:8)

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

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

其次,您可能遇到了Session对象的限制,导致多个请求使用session进行序列化,因为Session本身并不是多线程的。

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

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

[SessionState(SessionStateBehavior.Disabled)]
public class AjaxTestController : Controller
{        
    //...As above
}

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

[SessionState(SessionStateBehavior.ReadOnly)]
public class AjaxTestController : Controller
{        
    //...As above
}

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

答案 1 :(得分:3)

MVC 4.0中引入的一个重要特性是异步控制器,它可以编写异步操作方法。异步控制器允许在不使工作线程空闲的情况下执行操作。

调用异步操作时,会发生以下步骤:

Web服务器从线程池(工作线程)获取一个线程,并安排它来处理传入的请求。此工作线程启动异步操作。工作线程返回到线程池以服务另一个Web请求。异步操作完成后,它会通知ASP.NET。 Web服务器从线程池(可能是与启动异步操作的线程不同的线程)获取工作线程,以处理请求的其余部分,包括呈现响应。

将同步操作方法转换为异步操作方法

以下是同步操作方法及其异步等效版本的示例。

同步控制器:

public class TestController : Controller
 {
   public ActionResult Index()
    {
     return View(); 
    }
 }

以上操作的异步变体:

public class TestController : AsyncController
{
   public void IndexAsync()
   {
    return View();
   }

  public ActionResult IndexCompleted()
  {
   return View();
  }
}

步骤:

  • 同步控制器是从Controller派生的类 用于实现AsyncController而不是派生的类 来自Controller的控制器,从AsyncController类派生。 从AsyncController派生的控制器启用ASP.NET 处理异步请求,它们仍然可以服务同步 行动方法。

  • 对应同步中的同步动作方法 你需要为控制器创建两个方法 异步controller.First方法,启动异步 进程必须具有由操作和后缀组成的名称 &#34;异步&#34 ;.异步时调用的另一个方法 进程完成(回调方法)必须具有包含的名称 动作和后缀&#34;已完成&#34;。

在上面的示例示例中,Index操作已在异步控制器中转换为两个方法:IndexAsync和IndexCompleted。

当IndexCompleted方法返回ActionResult实例时,IndexAsync方法返回void。虽然操作包含两个方法,但使用与同步操作方法相同的URL(例如,Controller / Index)访问它。

请注意以下有关异步操作方法的内容:

  1. 如果操作名称为Sample,则框架将查找 SampleAsync和SampleCompleted方法。

  2. 查看页面应命名为Sample.aspx,而不是SampleAsync.aspx 或SampleCompleted.aspx。 (操作名称为Sample,而不是 SampleAsync)

  3. 控制器不能包含名为SampleAsync的异步方法 和一个名为Sample的同步方法。如果确实如此,那么 抛出AmbiguousMatchException异常,因为SampleAsync action方法和Sample action方法具有相同的请求 签名。

  4. 有关详情,请点击此处:http://www.counsellingbyabhi.com/2014/05/asynchronous-controllers-in-aspnet-mvc.html

答案 2 :(得分:0)

mvc控制器本质上是异步的,你是如何确定它是同步的?唯一的原因可能只是在userService中实现了一些锁。

您可以尝试使用jquery

对您的Web服务进行数百次ajax调用