也就是说针对当前Controller的AsyncManager的Finished事件的触发标志着异步操作的结束,而此时匹配的Completed方法会被执行。由于AsyncManager的Finish方法会主动触发该事件,所以我们可以通过调用该方法使Completed方法立即执行。由于AsyncManager的OperationCounter对象的Completed事件触发的时候会调用Finish方法,所以当表示当前正在执行的异步操作计算器的值为零时,Completed方法也会自动被执行。
如果我们在XxxAsync方法中通过如下的方式同时执行三个异步操作,并在每个操作完成之后调用AsyncManager的Finish方法,意味着最先完成的异步操作会导致XxxCompleted方法的执行。换句话说,当XxxCompleted方法执行的时候,可能还有两个异步操作正在执行。
AsyncManager.OutstandingOperations.Increment(3);
Task.Factory.StartNew(() =>
{
//异步操作1
AsyncManager.Finish();
});
Task.Factory.StartNew(() =>
{
//异步操作2
AsyncManager.Finish();
});
Task.Factory.StartNew(() =>
{
//异步操作3
AsyncManager.Finish();
});
如果完全通过为完成的异步操作计数机制来控制XxxCompleted方法的执行,由于计数的检测和Completed事件的触发只发生在OperationCounter的Increment/Decrement方法被执行的时候,如果我们在开始和结束异步操作的时候都没有调用这两个方法,XxxCompleted是否会执行呢?同样以之前定义的用语读取/显示文章内容的异步Action为例,我们按照如下的方式将定义在ArticleAsync方法中针对AsyncManager的OutstandingOperations属性的Increment和Decrement方法调用注释调用,ArticleCompleted方法是否还能正常运行呢?
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);
}
}
实际上ArticleCompleted依然会被执行,但是这样我们就不能确保正常读取文章内容,因为ArticleCompleted方法会在ArticleAsync方法执行之后被立即执行。如果文章内容读取是一个相对耗时的操作,表示文章内容的ArticleCompleted方法的content参数在执行的时候尚未被初始化。在这种情况下的ArticleCompleted是如何被执行的呢?
原因和简单,ReflectedAsyncActionDescriptor的BeginExecute方法在执行XxxAsync方法的前后会分别调用AsyncManager的OutstandingOperations属性的Increment和Decrement方法。对于我们给出的例子来说,在执行ArticleAsync之前Increment方法被调用使计算器的值变成1,随后ArticleAsync被执行,由于该方法以异步的方式读取指定的文件内容,所以会立即返回。最后Decrement方法被执行使计数器的值变成0,AsyncManager的Completed事件被触发并导致ArticleCompleted方法的执行。而此时,文件内容的读取正在进行之中,表示文章内容的content参数自然尚未被初始化。








