asp.net mvc源码分析-AsyncController
我们前面的讲的都是基于同步的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中获取。这里面的具体实现还是很复杂了,我们就滤过了吧。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构