在上面提供的实例中,我们在异步操作开始和结束的时候调用了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可以采用如下的定义方式。
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委托将会在该同步上下文中以同步的方式执行。
AsyncManager的核心是通过属性OutstandingOperations表示的正在进行的异步操作计数器,该属性是一个类型为OperationCounter的对象。操作计数通过只读属性Count表示,当我们开始和完成异步操作的时候分别调用Increment和Decrement方法作增加和介绍计数操作。Increment和Decrement各自具有两个重载,作为整数参数value(该参数值可以是负数)表示增加或者减少的数值,如果调用无参方法,增加或者减少的数值为1。如果我们需要同时执行多个异步操作,则可以通过如下的方法来操作计数器。