• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

通过一个模拟程序让你明白ASP.NET MVC是如何运行的

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

ASP.NET MVC的路由系统通过对HTTP请求的解析得到表示Controller、Action和其他相关的数据,并以此为依据激活Controller对象,调用相应的Action方法,并将方法返回的ActionResult写入HTTP回复中。为了更好的演示其实现原理,我创建一个简单的ASP.NET Web应用来模拟ASP.NET MVC的路由机制。这个例子中的相关组件基本上就是根据ASP.NET MVC的同名组件设计的,只是我将它们进行了最大限度的简化,因为我们只需要用它来演示大致的实现原理而已。[源代码从这里下载]

目录:
一、一个通过查询字符串表示Controller和Action的“MVC”程序
二、通过Route解析HTTP请求获得路由信息
三、在Global.asax中注册Route
四、Route的执行
五、通过MvcHandler处理请求
六、将ActionResult写入Http回复
七、实例的配置和定义

如右图所示,我们的Web应用非常简单。HomeController.cs为定义Controller类型的文件,而Index.html表示HomeController中名称为Index的Action对应的View。我们按照ASP.NET MVC的原理,通过解析请求URL得到Controller和Action的名称。如果Controller为Home,则激活HomeController,如果当前的Action为Index,则将Index.html这个静态文件的内容作为HTTP回复返回。

我不想定义复杂的解析Controller和Action的逻辑,再这里我直接通过请求URL相应的查询字符串controler和action表示Controller和Action的名称。也就是说如果通过浏览器访问地址http://localhost/mvcapp/?controller=Home&action=Index 可以访问到Index.html中的内容(注:我们并没有将Index.html作为站点的默认页面)。

接下来我简单的介绍一下是哪些组建促使这个简单的ASP.NET Web应用能够按照MVC的模式来执行。为了使你能够在真正的ASP.NET MVC找到匹配的组件,我们采用了相同的接口和类型名称。

二、通过Route解析HTTP请求获得路由信息

我定义了如下一个RouteData类型表示解析HTTP请求得到的Controller和Action等信息。Assemblies和Namespaces表示需要引入的命名空间和程序集,这是因为URL中只能解析出Controller的类型名称,需要相应的命名空间采用得到它的类型全名。如果对应的程序集不曾加载,还需要加载相应的程序集。

class RouteData
   2: {
string Controller { get; set; }
string Action { get; set; }
private set; }
private set; }
public IRouteHandler RouteHandler { get; set; }
   8:  
string action, IRouteHandler routeHandler)
  10:     {
this.Controller = controller;
this.Action = action;
this.RouteHandler = routeHandler;
this.Namespaces = RouteTable.Namespaces;
this.Assemblies = RouteTable.Assemblies;
  16:     }
  17: }

真正实现对HTTP请求进行解析并得到RouteData的Route继承自基类RouteBase。我们还定义个了一个表示Route集合的RouteCollection类型,它的GetRouteData方法对集合的所有Route对象进行遍历,并调用其GetRouteData方法。如果得到的RouteData不为空,则返回之。

class RouteBase
   2: {
abstract RouteData GetRouteData(HttpContextBase httpContext);
   4: }
   5:  
class RouteCollection: Collection<RouteBase>
   7: {
public RouteData GetRouteData(HttpContextBase httpContext)
   9:     {
this)
  11:         {
  12:             var routeData = route.GetRouteData(httpContext);
null != routeData)
  14:             {
return routeData;
  16:             }
  17:         }
null;
  19:     }
  20: }

和ASP.NET MVC一样,我们定义了如下一个RouteTable对象,其静态属性正是一个RouteCollection对象。两个静态属性Namespaces和Assemblies为命名空间和程序集名称的全局维护。

class RouteTable
   2: {
static RouteTable()
   4:     {
new RouteCollection();
string>();
string>();
   8:     }
private set; }
private set; }
private set; }
  12: }

而我们实例中完成基于查询字符串的Controller和Action解析的QueryStringRoute对应如下。在GetRouteData方法中,除了根据查询字符解析并初始化Controller和Action名称之外,还将RouteHandler指定为MvcRouteHandler。而MvcRouteHandler得GetHttpHandler方法直接返回的是根据RequestContext创建的MvcHandler对象。

class QueryStringRoute : RouteBase
   2: {
override RouteData GetRouteData(HttpContextBase httpContext)
   4:     {
) &&
) )
   7:         {
];
];
new MvcRouteHandler();
new RouteData(controller, action, routeHandler);               
  12:         }
null;
  14:     }
  15: }
  16:  
class MvcRouteHandler: IRouteHandler
  18: {
public IHttpHandler GetHttpHandler(RequestContext requestContext)
  20:     {
new MvcHandler(requestContext);
  22:     }
  23: }

三、在Global.asax中注册Route

通过上面定义的RouteTable类型,我们在Global.asax中按照如下的方式在应用启动的时候QueryStringRoute对象添加到RouteTable的静态属性Routes表示的Route列表中。同时为需要的命名空间和程序集名称进行初始化,以辅助后续步骤中对Controller的创建。

class Global : System.Web.HttpApplication
   2: {
object sender, EventArgs e)
   4:     {
new QueryStringRoute());
);
);
   8:     }
   9: }

四、Route的执行

通过RouteTable的Routes属性表示的Route列表对请求的解析和路由信息的获取是通过自定义的HttpModule来实现的,它的类型为UrlRoutingModule。如下面的代码片断所示,UrlRoutingModule注册了HttpApplication的PostResolveRequestCache事件,并在该事件触发的时候调用Route列表的GetRouteData方法,并根据得到RouteData创建RequestContext。最后通过RouteData的RouteHandler得到真正用于处理该请求的HttpHandler对象,并对其进行映射。这意味着后续将会采用这个映射的HttpHandler进行请求的处理。

class UrlRoutingModule: IHttpModule
   2: {
void Dispose() { }
void Init(HttpApplication context)
   5:     {
   6:         context.PostResolveRequestCache += (sender, args) =>
   7:             {
new HttpContextWrapper(context.Context);
   9:                 HttpContextBase httpContext = (HttpContextBase)contextWrapper;
  10:                 RouteData routeData = RouteTable.Routes.GetRouteData(httpContext);
null == routeData)
  12:                 {
return;
  14:                 }
new RequestContext { HttpContext = httpContext, RouteData = routeData };                    
  16:                 httpContext.RemapHandler(routeData.RouteHandler.GetHttpHandler(requestContext));
  17:             };
  18:     }
  19: }

五、通过MvcHandler处理请求

在UrlRoutingModule映射的实际上是具有如下定义的MvcHandler,它具有一个RequestContext属性通过构造函数进行初始化。在ASP.NET MVC中,真正的请求处理体现在根据路由信息创建Controller,并执行相应的Action方法。这两个步骤体现的ProcessRequest方法中。

class MvcHandler: IHttpHandler
   2: {
private set;}
public IControllerFactory ControllerFactory
   5:     {
return ControllerBuilder.Current.GetControllerFactory(); }
   7:     }
public MvcHandler(RequestContext requestContext)
   9:     {
this.RequestContext = requestContext;
  11:     }
bool IsReusable
  13:     {
false; }
  15:     }
void ProcessRequest(HttpContext context)
  17:     {
this.RequestContext.RouteData;
this.RequestContext, routeData.Controller);
this.RequestContext);
  21:     }
  22: }

Controller实现了具有如下定义的接口IController,所有Action方法都通过Execute方法执行,该方法的参数的表示当前请求上下文的RequestContext对象。IController通过相应的Controller工厂创建,下面的代码同时也定义了Controller工厂接口的定义。

interface IController
   2: {
void Execute(RequestContext requestContext);
   4: }
interface IControllerFactory
   6: {
string controllerName);
   8: }

我们定义了如下一个简单名称为DefaultController,它的Execute方法定义很简单:通过包含在RequestContext的RouteData得到当前的Action,并将它作为方法名得到相应的MethodInfo对象,滨个通过反射调用它得到一个ActionResult对象,最后执行ActionResult的ExecuteResult方法。该方法的参数是基于RequestContext创建的另一个上下文ControllerContext。

class DefaultController : IController
   2: {
void Execute(RequestContext requestContext)
   4:     {
string action = requestContext.RouteData.Action;
this.GetType().GetMethod(action);
null);
new ControllerContext
   9:         {
  10:             RequestContext = requestContext
  11:         };
  12:         result.ExecuteResult(controllerContext);
  13:     }
  14: }

我们定义了具有如下定义的Controller工厂类DefaultControllerFactory。创建Controller的逻辑也不复杂:通过RouteData表示的Controller名称得到相应的Controller类型,通过反射创建Controller对象。由于RouteData中只包含Controller的名称,所以需要通过命名空间和程序集的辅助才能解析出真正的类型。

class DefaultControllerFactory : IControllerFactory
   2: {
string controllerName)
   4:     {
   5:         RouteData routeData = requestContext.RouteData;
, controllerName);
   7:         IController controller;
this.CreateControler(controllerType);
null != controller)
  10:         {
return controller;
  12:         }
in routeData.Assemblies)
  14:         {
this.Cre 

鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
Asp.Net中使用Couchbase——Memcached缓存入门篇发布时间:2022-07-10
下一篇:
ASP.NET下载文件(弹出打开保存文件对话框)发布时间:2022-07-10
热门推荐
热门话题
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap