【问题标题】:How to make ASP.NET MVC Controller Methods Async如何使 ASP.NET MVC 控制器方法异步
【发布时间】:2014-06-12 02:56:34
【问题描述】:

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

为了解决这个问题,我尝试使有问题的控制器方法异步。我通过以下方式做到了这一点

  1. 将异步附加到控制器方法名称
  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
        };
    } 

但它似乎仍然是同步的。我是否遗漏了什么或完全错误的方式?我并没有真正使用任务库,所以可能会遗漏一些重要的东西?

【问题讨论】:

  • 顺便说一句,在 ASP.NET 中使用 Task.Factory.StartNew()Task.Run() 通常没有多大意义。而且将它们组合当然没有任何意义。

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


【解决方案1】:

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

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

其次,您可能遇到了 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
}

但对于浏览器限制,您无能为力,因为不同的浏览器有特定的请求限制。这些可以通过注册表(或浏览器配置)条目(通常)进行更改,但在大多数情况下,您不能强制用户这样做。

【讨论】:

  • 看起来将会话设置为禁用或只读可以解决问题。在我找到的异步控制器示例中没有看到任何提及。非常感谢
  • @Gavin - 这是因为问题与异步无关。异步用于获得更好的资源可扩展性。这个问题是特定于会话的。
  • @Gavin - 顺便说一下,这是 XY 问题的经典示例。 meta.stackexchange.com/questions/66377/what-is-the-xy-problem - 你有一个问题,你的请求正在被序列化,所以你认为问题是因为你没有使用异步......所以你询问异步而不是询问你的真正问题,序列化控制器方法。跨度>
【解决方案2】:

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

步骤:

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

  • 对应Synchronous中的同步动作方式 控制器,您需要为其中的操作创建两个方法 异步控制器。启动异步的第一个方法 进程的名称必须由操作和后缀组成 “异步”。异步时调用的另一个方法 进程完成(回调方法)的名称必须包含 动作和后缀“已完成”。

在上面的示例中,Index 动作在异步控制器中变成了两个方法:IndexAsync 和 IndexCompleted。

IndexAsync 方法返回 void,而 IndexCompleted 方法返回一个 ActionResult 实例。尽管该操作由两个方法组成,但使用与同步操作方法相同的 URL(例如,Controller/Index)来访问它。

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

  1. 如果动作名称是 Sample,框架将寻找 SampleAsync 和 SampleCompleted 方法。

  2. 视图页面应命名为 Sample.aspx 而不是 SampleAsync.aspx 或 SampleCompleted.aspx。 (动作名称是 Sample,而不是 SampleAsync)

  3. 控制器不能包含名为 SampleAsync 的异步方法 和一个名为 Sample 的同步方法。如果是这样,一个 引发 AmbiguousMatchException 异常,因为 SampleAsync action 方法和 Sample action 方法具有相同的请求 签名。

更多详情请点击:http://www.counsellingbyabhi.com/2014/05/asynchronous-controllers-in-aspnet-mvc.html

【讨论】:

  • 很好的答案.. void 方法如何返回任何东西?是不是笔误?
【解决方案3】:

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

您可以尝试使用 jquery 对您的网络服务进行数百次 ajax 调用

【讨论】:

  • 这是因为 Visual Studio 调试器附加到 iis 工作进程/iis express 进程,iis 被设计为使用线程池处理请求blogs.msdn.com/b/tmarq/archive/2007/07/21/…。删除所有断点并尝试在客户端使用 ajax,然后生成几个,然后查看所有断点都会在控制器收到结果后立即得到响应
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-14
  • 1970-01-01
  • 1970-01-01
  • 2012-10-29
  • 1970-01-01
  • 2014-07-14
相关资源
最近更新 更多