我们前面的讲的都是基于同步的Controller来实现,现在我们来看看基于异步的AsyncController又是如何实现的。
首先看一个demo吧:
public void IndexAsync() { //实现异步action加计数1 FileStream fileStream = new FileStream(@"D:\channel.txt", FileMode.Open); byte[] byteArray = new byte[fileStream.Length]; fileStream.BeginRead(byteArray, 0, (int)fileStream.Length, (IAsyncResult result) => { string content = Encoding.Default.GetString(byteArray); //参数要放在这个字典里面实现向Completed action传递 AsyncManager.Parameters["content"] = content; //异步action回调结束 fileStream.Close(); }, null); } //这个action以Completed为后缀异步action结束后调用的函数,返回值为ActionResult public ActionResult IndexCompleted(string content) { return Content(content); }
网上对AsyncController也有些意见
此外还要另外注意几点:
1.对于异步请求,当发起另外一个线程去处理请求没有返回怎么办,比如抛出异常?框架默认的超时时间是45秒,在45秒到了之后框架会抛出一个System.TimeoutException以中止这个异步请求,我们可以通过[AsyncTimeOut((int duration)]来设置超时时间,还可以通过NoAsyncTimeout或者[AsyncTimeout(Timeout.Infinite)]来设置永不过期。
2.可以使用AsyncManager.Finish方法来中止所有还未结束的异步操作,进而调用Completed action,如果被强制中止的异步操作还没有成功返回某些参数时,Completed将使用这些参数的默认值(如int为0,string为empty)。
3.AsyncManager.Sync方法的作用
我喜欢看看源代码,知道这一切都是为什么。我一次做AsyncController我的问题是它是这么调用回调函数的,参数又是如何获取的了。
首先看看AsyncController 的定义:
public abstract class AsyncController : Controller, IAsyncManagerContainer, IAsyncController
public interface IAsyncController : IController { IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state); void EndExecute(IAsyncResult asyncResult); }
public interface IAsyncManagerContainer { AsyncManager AsyncManager { get;} }
从这里我们知道AsyncController实现了异步的效果,同时里面还有一个AsyncManager ,我们知道执行Action的一个关键类是ControllerActionInvoker类,在AsyncController应该创建一个和它差不多的类啊?实现这个功能的在这句代码:
protected override IActionInvoker CreateActionInvoker() { return new AsyncControllerActionInvoker(); }
public class AsyncControllerActionInvoker : ControllerActionInvoker, IAsyncActionInvoker
从AsyncControllerActionInvoker 的定义我们知道它实现了异步功能。它的结构和我们的ControllerActionInvoker相差不大,在它的GetControllerDescriptor方法中有这么一句:ControllerDescriptor controllerDescriptor = DescriptorCache.GetDescriptor(controllerType, () => newReflectedAsyncControllerDescriptor(controllerType));
而ReflectedAsyncControllerDescriptor和ReflectedControllerDescriptor类相差不大,只不过ReflectedControllerDescriptor里面用到了ActionMethodSelector查找参数,而ReflectedAsyncControllerDescriptor用的是AsyncActionMethodSelector查找参数。
在AsyncActionMethodSelector的GetActionDescriptorDelegate方法中有点特殊:
private ActionDescriptorCreator GetActionDescriptorDelegate(MethodInfo entryMethod) { // Is this the FooAsync() / FooCompleted() pattern? if (IsAsyncSuffixedMethod(entryMethod)) { string completionMethodName = entryMethod.Name.Substring(0, entryMethod.Name.Length - "Async".Length) + "Completed"; MethodInfo completionMethod = GetMethodByName(completionMethodName); if (completionMethod != null) { return (actionName, controllerDescriptor) => new ReflectedAsyncActionDescriptor(entryMethod, completionMethod, actionName, controllerDescriptor); } else { throw Error.AsyncActionMethodSelector_CouldNotFindMethod(completionMethodName, ControllerType); } }
// Fallback to synchronous method return (actionName, controllerDescriptor) => new ReflectedActionDescriptor(entryMethod, actionName, controllerDescriptor); } private static bool IsAsyncSuffixedMethod(MethodInfo methodInfo) { return methodInfo.Name.EndsWith("Async", StringComparison.OrdinalIgnoreCase); }
从这里我们知道我们的方法名应该命名位xxxAsync()->xxxCompleted()这个格式,系统会自己调用对应的回调方法。也只有以这种命名了的方法才是真正实现了异步的,不然又返回一个普通的ReflectedActionDescriptor,在这里我们可以猜测ReflectedAsyncActionDescriptor应该是实现了异步模式的。
public class ReflectedAsyncActionDescriptor : AsyncActionDescriptor
在ReflectedAsyncActionDescriptor的BeginExecute方法中主要内容如下:
AsyncManager asyncManager = GetAsyncManager(controllerContext.Controller); BeginInvokeDelegate beginDelegate = delegate(AsyncCallback asyncCallback, object asyncState) { // call the XxxAsync() method ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(AsyncMethodInfo); dispatcher.Execute(controllerContext.Controller, parametersArray); // ignore return value from this method return asyncResult; }; EndInvokeDelegate<object> endDelegate = delegate(IAsyncResult asyncResult) { // call the XxxCompleted() method ParameterInfo[] completionParametersInfos = CompletedMethodInfo.GetParameters(); var rawCompletionParameterValues = from parameterInfo in completionParametersInfos select ExtractParameterOrDefaultFromDictionary(parameterInfo,asyncManager.Parameters); object[] completionParametersArray = rawCompletionParameterValues.ToArray(); ActionMethodDispatcher dispatcher = DispatcherCache.GetDispatcher(CompletedMethodInfo); object actionReturnValue = dispatcher.Execute(controllerContext.Controller, completionParametersArray); return actionReturnValue; }; return AsyncResultWrapper.Begin(callback, state, beginDelegate, endDelegate, _executeTag, asyncManager.Timeout);
从这里我们就可以确定程序在调用了XxxAsync之后会自动调用XxxCompleted方法,XxxCompleted所需参数的值会从AsyncManager。Parameters中获取。这里面的具体实现还是很复杂了,我们就滤过了吧。
|
请发表评论