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

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

ReflectedAsyncActionDescriptor这样的执行机制也对我们使用AsyncManager提出了要求,那就是对尚未完成的一步操作计数器的增加操作不应该发生在异步线程中,如下所示的针对AsyncManager的OutstandingOperations属性的Increment方法的定义是不对的。

  public class HomeController AsyncController
   {
     public void XxxAsync(string name)
     {
       Task.Factory.StartNew(() =>
         {
           AsyncManager.OutstandingOperations.Increment();
            //...
            AsyncManager.OutstandingOperations.Decrement();
        });
    }
    //其他成员
  } 

下面采用正确的定义方法:

 public class HomeController AsyncController
   {
     public void XxxAsync(string name)
    {
      AsyncManager.OutstandingOperations.Increment();
       Task.Factory.StartNew(() =>
         {
           //...
           AsyncManager.OutstandingOperations.Decrement();
        });
    }
    //其他成员
  } 

最后再强调一点,不论是显式调用AsyncManager的Finish方法,还是通过调用AsyncManager的OutstandingOperations属性的Increment方法是计数器的值变成零,仅仅是让XxxCompleted方法得以执行,并不能真正阻止异步操作的执行。

五、异步操作的超时控制

异步操作虽然适合那些相对耗时的I/O绑定型操作,但是也并不说对一步操作执行的时间没有限制。异步超时时限通过AsyncManager的整型属性Timeout表示,它表示超时时限的总毫秒数,其默认值为45000(45秒)。如果将Timeout属性设置为-1,意味着异步操作执行不再具有任何时间的限制。对于以XxxAsync/XxxCompleted形式定义的异步Action来说,如果XxxAsync执行之后,在规定的超时时限中XxxCompleted没有得到执行,一个TimeoutException会被抛出来。

如果我们以返回类型为Task的形式定义异步Action,通过Task体现的异步操作的执行时间不受AsyncManager的Timeout属性的限制。我们通过如下的代码定义了一个名为Data的异步Action方法以异步的方式获取作为Model的数据并通过默认的View呈现出来,但是异步操作中具有一个无限循环,当我们访问该Data方法时,异步操作将会无限制地执行下去,也不会有TimeoutException异常发生。

  public class HomeController AsyncController
   {
     public Task<ActionResult> Data()
     {
       return Task.Factory.StartNew(() =>
       {
         while (true)
         { }
         return GetModel();
          
      }).ContinueWith<ActionResult>(task =>
      {
        object model = task.Result;
        return View(task.Result);
      });
    }
    //其他成员
  }

在ASP.NET MVC应用编程接口中具有两个特殊的特性用于定制异步操作执行的超时时限,它们是具有如下定义的AsyncTimeoutAttribute和NoAsyncTimeoutAttribute,均定义在命名空间System.Web.Mvc下。