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

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

 public class HomeController AsyncController
   {
     public Task<ActionResult> Article(string name)
     {
       return 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();
          }
        }).ContinueWith<ActionResult>(task =>
          {
            string content = (string)AsyncManager.Parameters["content"];
            return Content(content);
          });
    }
  }

上面定义的异步Action方法Article的返回类型为Task<ActionResult>,我们将异步文件内容的读取体现在返回的Task对象中。对文件内容呈现的回调操作则通过调用该Task对象的ContinueWith<ActionResult>方法进行注册,该操作会在异步操作完成之后被自动调用。

如上面的代码片断所示,我们依然利用AsyncManager的Parameters属性实现参数在异步操作和回调操作之间的传递。其实我们也可以使用Task对象的Result属性来实现相同的功能,Article方法的定义也改写成如下的形式。

 public class HomeController AsyncController
   {
     public Task<ActionResult> Article(string name)
     {
       return Task.Factory.StartNew(() =>
         {
           string path = ControllerContext.HttpContext.Server.MapPath(string.Format(@"articles{0}.html", name));
           using (StreamReader reader = new StreamReader(path))
           {
            return reader.ReadToEnd();
          }
        }).ContinueWith<ActionResult>(task =>
          {          
            return Content((string)task.Result);
          });
    }
  }

三、AsyncManager

在上面演示的异步Action的定义中,我们通过AsyncManager实现了两个基本的功能,即在异步操作和回调操作之间传递参数和向ASP.NET MVC发送异步操作开始和结束的通知。由于AsyncManager在异步Action场景中具有重要的作用,我们有必要对其进行单独介绍,下面是AsyncManager的定义。

 public class AsyncManager
   {  
     public AsyncManager();
     public AsyncManager(SynchronizationContext syncContext);
   
     public EventHandler Finished;
   
     public virtual void Finish();
     public virtual void Sync(Action action);
    
    public OperationCounter OutstandingOperations { get; }
    public IDictionary<string, object> Parameters { get; }
    public int Timeout { get; set; }
  }
   
  public sealed class OperationCounter
  {
    public event EventHandler Completed;  
    
    public int Increment();
    public int Increment(int value);
    public int Decrement();
    public int Decrement(int value);
    
    public int Count { get; }
  }

如上面的代码片断所示,AsyncManager具有两个构造函数重载,非默认构造函数接受一个表示同步上下文的SynchronizationContext对象作为参数。如果指定的同步上下文对象为Null,并且当前的同步上下文(通过SynchronizationContext的静态属性Current表示)存在,则使用该上下文;否则创建一个新的同步上下文。该同步上下文用于Sync方法的执行,也就是说在该方法指定的Action委托将会在该同步上下文中以同步的方式执行。