详解ASP.NET MVC下的异步Action的定义和执行原理

2019-05-26 01:31:58于丽

二、两种异步Action方法的定义

在了解了在AsyncController中定义异步Action方法的必要性之后,我们来简单介绍一下异步Action方法的定义方式。总的来说,异步Action方法具有两种定义方式,一种是将其定义成两个匹配的方法XxxAsync/XxxCompleted,另一种则是定义一个返回类型为Task的方法。

XxxAsync/XxxCompleted

如果我们使用两个匹配的方法XxxAsync/XxxCompleted来定义异步Action,我们可以将异步操作实现在XxxAsync方法中,而将最终内容的呈现实现在XxxCompleted方法中。XxxCompleted可以看成是针对XxxAsync的回调,当定义在XxxAsync方法中的操作以异步方式执行完成后,XxxCompleted方法会被自动调用。XxxCompleted的定义方式和普通的同步Action方法比较类似。

作为演示,我在如下一个HomeController中定义了一个名为Article的异步操作来呈现指定名称的文章内容。我们将指定文章内容的异步读取定义在ArticleAsync方法中,而在ArticleCompleted方法中讲读取的内容以ContentResult的形式呈现出来。

public class HomeController : AsyncController
   {
     public void ArticleAsync(string name)
     {
       AsyncManager.OutstandingOperations.Increment();
       Task.Factory.StartNew(() =>
         {
           string path = ControllerContext.HttpContext.Server.MapPath(string.Format(@"articles{0}.html", name));
           using (StreamReader reader = new StreamReader(path))
          {
            AsyncManager.Parameters["content"] = reader.ReadToEnd();
          }
          AsyncManager.OutstandingOperations.Decrement();
        });
    }
    public ActionResult ArticleCompleted(string content)
    {
      return Content(content);
    }
  } 

对于以XxxAsync/XxxCompleted形式定义的异步Action方法来说,ASP.NET MVC并不会以异步的方式来调用XxxAsync方法,所以我们需要在该方法中自定义实现异步操作的执行。在上面定义的ArticleAsync方法中,我们是通过基于Task的并行编程方式来实现对文章内容的异步读取的。当我们以XxxAsync/XxxCompleted形式定义的异步Action方法的时候,会频繁地使用到Controller的AsyncManager属性,该属性返回一个类型为AsyncManager对象,我们将在下面一节对其进行单独讲述。

在上面提供的实例中,我们在异步操作开始和结束的时候调用了AsyncManager的OutstandingOperations属性的Increment和Decrement方法对于ASP.NET MVC发起通知。此外,我们还利用AsyncManager的Parameters属性表示的字典来保存传递给ArticleCompleted方法的参数,参数在字典中的Key(content)与ArticleCompleted的参数名称是匹配的,所以在调用方法ArticleCompleted的时候,通过AsyncManager的Parameters属性指定的参数值将自动作为对应的参数值。

Task返回值

如果采用上面的异步Action定义方式,意味着我们不得不为一个Action定义两个方法,实际上我们可以通过一个方法来完成对异步Action的定义,那就是让Action方法返回一个代表异步操作的Task对象。上面通过XxxAsync/XxxCompleted形式定义的异步Action可以采用如下的定义方式。