没有找到合适的产品?
联系客服协助选型:023-68661681
提供3000多款全球软件/控件产品
针对软件研发的各个阶段提供专业培训与技术咨询
根据客户需求提供定制化的软件开发服务
全球知名设计软件,显著提升设计质量
打造以经营为中心,实现生产过程透明化管理
帮助企业合理产能分配,提高资源利用率
快速打造数字化生产线,实现全流程追溯
生产过程精准追溯,满足企业合规要求
以六西格玛为理论基础,实现产品质量全数字化管理
通过大屏电子看板,实现车间透明化管理
对设备进行全生命周期管理,提高设备综合利用率
实现设备数据的实时采集与监控
利用数字化技术提升油气勘探的效率和成功率
钻井计划优化、实时监控和风险评估
提供业务洞察与决策支持实现数据驱动决策
原创|其它|编辑:郝浩|2009-04-21 10:53:16.000|阅读 456 次
概述:异步请求处理是ASP.NET 2.0中引入的高级特性,它依托IO Complete Port,对于提高IO密集型应用程序的吞吐量非常重要(详见原理描述和性能测试)。
# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>
异步请求处理是ASP.NET 2.0中引入的高级特性,它依托IO Complete Port,对于提高IO密集型应用程序的吞吐量非常重要(详见原理描述和性能测试)。 但是目前ASP.NET MVC框架缺少异步Action功能,这也就是老赵经常挂在嘴边的那个“目前ASP.NET MVC所缺少的非常重要的功能”。在TechED 2008 China的Session中我曾经给出过一个所谓的“解决方案”,但是它复杂性之高使那个解决方案有太多限制。为了弥补TechED上的遗憾,以及准 备.NET开发大会上的ASP.NET MVC最佳实践的Session,我在春节休假期间仔细思考了一下这方面的问题,得出了一个相对不错的扩展:完整,方便,并且非常轻巧——核心逻辑代码只 有200行左右,这意味着绝大部分功能将会委托给框架中现成的内容,确保了扩展的稳定,高效并且拥有较好的向后兼容性。
值得一提的是,在1/26号便基于ASP.NET MVC的Beta版本写出了这个扩展的第一个版本,而在不久之后微软发布了ASP.NET MVC RC。在移植解决方案的过程中发现ASP.NET MVC RC在框架设计上进行了较大的改进,这使得在构建扩展时的策略发生了些许变化。令人欣喜的是,RC版本的这些变化对于构建一个扩展,尤其是现在这种“低 端”级别的扩展变得更加容易。ASP.NET MVC框架实现了它“到处可扩展”的承诺。
那么我们现在就来详细分析一下这个扩展的实现方式。
请求处理方式的改变
在制定基本改造策略之前,我们需要了解ASP.NET MVC框架目前的架构及请求处理流程。如下:
在应用程序启动时(此时还没有接受任何请求),将针对MVC请求的Route策略注册至ASP.NET Routing模块。此时每个Route策略(即Route对象)中的RouteHandler属性为ASP.NET MVC框架中的MvcRouteHandler。
当ASP.NET Routing模块接收到一个匹配某个Route策略的HTTP请求时,将会调用该Route对象中RouteHandler对象的 GetHttpHandler以获取一个HttpHandler,并交由ASP.NET执行。MvcRouteHandler永远将返回一个 MvcHandler对象。
MvcHandler在执行时,将取出RouteData中的controller值,并以此构建一个实现了IController接口的控制器对象,并调用IController接口的Execute方法执行该控制器。
对 于一个ASP.NET MVC应用程序来说,大部分控制器将会继承System.Web.Mvc.Controller类型。Controller类将会从RouteData获 取action值,并交给实现IActionInvoker接口的对象来执行一个Action。
……
如果我们要将这个流程改造 成异步处理,那么就要让它符合ASP.NET架构中的异步处理方式。ASP.NET架构对于异步请求的处理可以体现在好几种方式上,例如异步页面,异步 Http Module等,而最适合目前场合的做法自然是异步Http Handler。为实现一个异步Handler,我们需要让处理请求的Handler实现IHttpAsyncHandler接口,而不是传统的 IHttpHandler接口。IHttpAsyncHandler接口中的BeginProcessRequest和 EndProcessRequest两个方法构成了.NET中的APM(Aynchronous Programming Model,异步编程模型)模式,可以使用“二段式”的异步调用来处理一个HTTP请求。
您应该已经发现,如果我们要支持异步Action,就必须根据当前的请求信息来确认究竟是执行一个IHttpHandler对象还是 IHttpAsyncHandler对象。而在ASP.NET MVC框架在默认情况下是在Http Handler(即MvcHandler对象)内部进行控制器的检查,构造和调用。这为时已晚,我们必须讲这些逻辑提前到Routing过程中才行。幸运 的是,ASP.NET Routing所支持的IRouteHandler就像是ASP.NET中的IHttpHandlerFactory,可以根据情况生成不同的 Handler来执行。因此,我们只要构建一个新的IRouteHandler类型即可。
于是就诞生了AsyncMvcRouteHandler——可以想象的出,其中的部分代码与框架中的MvcHandler相同,因为在一定程度上我们的确只是把原本在MvcHandler里做的事情给提前了:
public class AsyncMvcRouteHandler : IRouteHandler
{
public IHttpHandler GetHttpHandler(RequestContext requestContext)
{
string controllerName = requestContext.RouteData.GetRequiredString("controller");
var factory = ControllerBuilder.Current.GetControllerFactory();
var controller = factory.CreateController(requestContext, controllerName);
if (controller == null)
{
throw new InvalidOperationException(...);
}
var coreController = controller as Controller;
if (coreController == null)
{
return new SyncMvcHandler(controller, factory, requestContext);
}
else
{
string actionName = requestContext.RouteData.GetRequiredString("action");
return IsAsyncAction(coreController, actionName, requestContext)
(IHttpHandler)new AsyncMvcHandler(coreController, factory, requestContext) :
(IHttpHandler)new SyncMvcHandler(controller, factory, requestContext);
}
}
internal static bool IsAsyncAction(
Controller controller, string actionName, RequestContext requestContext)
{
...
}
}
在GetHttpHandler方法中,我们先从RouteData的controller字段中获取控制器的名字,并通过注册在 ControllerBuilder上的Factory来创建一个实现了IController接口的控制器对象。由于我们需要使用Controller 类中包含的ActionInvoker来辅助检测Action的异步需求,因此我们会设法将其转化为Controller类型。如果转换成功,就会取出 RouteData中的action字段的值,并通过IsAsyncAction方法来确认当前Action是否应该异步执行。如果是,则返回一个实现了 IHttpAsyncHandler的AsyncMvcHandler对象,否则就返回一个实现IHttpHandler的SyncMvcHandler 对象。
至于AsyncMvcRouteHandler的使用,只需在MapRoute时将Route Handler重新设置一下即可:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
).RouteHandler = new AsyncMvcRouteHandler();
}
检查是否为异步Action
从上面的代码中我们已经形成了一个约定:如果要执行一个异步Action,那么控制器对象必须为 Controller类型。这个约定的目的是为了使用Controller类中包含的IActionInvoker——确切地说,是 ControllerActionInvoker类型里的功能。因此,另一个约定便是Controller的ActionInvoker对象必须返回一个 ControllerActionInvoker的实例。
执行Action方法
对于执行同步Action的SyncMvcHandler,其实现十分简单而直接:
public class SyncMvcHandler : IHttpHandler, IRequiresSessionState
{
public SyncMvcHandler(
IController controller,
IControllerFactory controllerFactory,
RequestContext requestContext)
{
this.Controller = controller;
this.ControllerFactory = controllerFactory;
this.RequestContext = requestContext;
}
public IController Controller { get; private set; }
public RequestContext RequestContext { get; private set; }
public IControllerFactory ControllerFactory { get; private set; }
public virtual bool IsReusable { get { return false; } }
public virtual void ProcessRequest(HttpContext context)
{
try
{
this.Controller.Execute(this.RequestContext);
}
finally
{
this.ControllerFactory.ReleaseController(this.Controller);
}
}
}
而对于异步Action,我之前一直思考着怎么将框架的默认实现,也就是单个方法调用,转化成两个方法(BeginXxx/EndXxx)调用。曾经我 想过自己实现一个新的ActionInvoker,但是这就涉及到了大量的工作,尤其是如果希望保持框架现有的功能 (ActionFilter,ActionSelector等等),最省力的方法可能就是继承ControllerActionInvoker,并设法使 用框架已经实现的各种辅助方法。但是在分析了框架代码之后我发现复用也非常困难,举例来说,ControllerActionInvoker判定一个方法 为Action的依据之一是这个方法返回的是ActionResult类型或其子类,这意味着我无法直接使用这个方法来获取一个返回 IAsyncResult的BeginXxx方法;同理,对于查找EndXxx方法,我可能需要在请求名为Abc的异步Action时,将EndAbc作 为查找依据交由现成的方法来查询——但是,如果又有一个请求是直接针对一个名为EndAbc的同步Action的那又怎么办呢
由于这些问题存在,我在去年设法实现异步Action时几乎重写了整个ActionInvoker——其复杂程度可见一斑。而且那个实现对于一 些特殊情况的处理依旧不甚友好,需要开发人员在一定程度上做出妥协。这个实现在TechED 2008 China的Session中公布时我就承认它并不能让我满意,建议大家不要将其投入生产环境中。而现在的实现,则非常顺利地解决了整个问题。虽然从理论 上讲还不够“完美”,虽然还做出了一些让步。
带来如此多问题的原因就在于我们在设法颠覆框架内部的关键性设计,也就是从单一的Action方法调用,转变为“符合APM的”二段式调用。等 等,您是否感觉到了解决问题的关键没错,那就是“符合APM的”。APM要求我们将一个行为分为BeginXxx和EndXxx两个方法,可是既然 ASP.NET MVC框架只能让我们返回一个ActionResult对象……那么我们为什么不在这个对象里包含方法的引用——也就是一个委托对象呢这虽然不符合正统的 APM签名,但是完全可行,不是吗
public class AsyncActionResult : ActionResult
{
public AsyncActionResult(
IAsyncResult asyncResult,
Func<IAsyncResult, ActionResult> endDelegate)
{
this.AsyncResult = asyncResult;
this.EndDelegate = endDelegate;
}
public IAsyncResult AsyncResult { get; private set; }
public Func<IAsyncResult, ActionResult> EndDelegate { get; private set; }
public override void ExecuteResult(ControllerContext context)
{
context.Controller
.SetAsyncResult(this.AsyncResult)
.SetAsyncEndDelegate(this.EndDelegate);
}
}
由于在Action方法中可以调用BeginXxx方法,我们在AsyncActionResult中只需保留Begin方法返回的 IAsyncResult,以及另一个对于EndXxx方法的引用。在AsyncActionResult的ExecuteResult方法中将会保存这 两个对象,以便在AsyncMvcHandler的EndProcessRequest方法中重新获取并使用。根据“惯例”,
我们还需要定义一个扩展方法,方便开发人员在Action方法中返回一个AsyncActionResult。具体实现非常容易,在这里就展示一下异步Action的编写方式:
[AsyncAction]
public ActionResult AsyncAction(AsyncCallback asyncCallback, object asyncState)
{
SqlConnection conn = new SqlConnection("...;Asynchronous Processing=true");
SqlCommand cmd = new SqlCommand("WAITFOR DELAY '00:00:03';", conn);
conn.Open();
return this.Async(
cmd.BeginExecuteNonQuery(asyncCallback, asyncState),
(ar) =>
{
int value = cmd.EndExecuteNonQuery(ar);
conn.Close();
return this.View();
});
}
至此,似乎AsyncMvcHandler也无甚秘密可言了:
public class AsyncMvcHandler : IHttpAsyncHandler, IRequiresSessionState
{
public AsyncMvcHandler(
Controller controller,
IControllerFactory controllerFactory,
RequestContext requestContext)
{
this.Controller = controller;
this.ControllerFactory = controllerFactory;
this.RequestContext = requestContext;
}
}
本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@evget.com
文章转载自:自互联网面对“数字中国”建设和中国制造2025战略实施的机遇期,中车信息公司紧跟时代的步伐,以“集约化、专业化、标准化、精益化、一体化、平台化”为工作目标,大力推进信息服务、工业软件等核心产品及业务的发展。在慧都3D解决方案的实施下,清软英泰建成了多模型来源的综合轻量化显示平台、实现文件不失真的百倍压缩比、针对模型中的大模型文件,在展示平台上进行流畅展示,提升工作效率,优化了使用体验。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
本站的模型资源均免费下载,登录后即可下载。模型仅供学习交流,勿做商业用途。
服务电话
重庆/ 023-68661681
华东/ 13452821722
华南/ 18100878085
华北/ 17347785263
客户支持
技术支持咨询服务
服务热线:400-700-1020
邮箱:sales@evget.com
关注我们
地址 : 重庆市九龙坡区火炬大道69号6幢
慧都科技 版权所有 Copyright 2003-
2025 渝ICP备12000582号-13 渝公网安备
50010702500608号