您的位置:首页 > 编程语言 > ASP

asp.net mvc源码分析-AsyncController

2012-11-13 16:11 531 查看
我们前面的讲的都是基于同步的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中获取。这里面的具体实现还是很复杂了,我们就滤过了吧。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: