您现在的位置是:网站首页> 编程资料编程资料
详解ASP.NET MVC的整个生命周期_实用技巧_
2023-05-24
387人已围观
简介 详解ASP.NET MVC的整个生命周期_实用技巧_
一、介绍
我们做开发的,尤其是做微软技术栈的,有一个方向是跳不过去的,那就是MVC开发。我相信大家,做ASP.NET MVC 开发有的有很长时间,当然,也有刚进入这个行业的。无论如何,如果有人问你,你知道ASP.NET MVC的生命周期吗?你知道它的来世今生吗?你知道它和 ASP.NET WEBFORM 有什么区别吗?估计,这些问题,有很多人会答不上来,或者说不清楚。今天,我就把我的理解写出来,也是对我自己学习的一次回顾和总结吧。当然,由于本人能力有限,在写的过程中也可能会有一些错误,希望大家多多包涵,当然,更希望大家能不灵赐教,我们共同进步。
在开始之前,我们先来说说,ASP.NET Web Form 和 Asp.net MVC 有什么区别,这里说的区别,当然是本质区别,不是适用语法那个层次的。其实,说起来,ASP.NET WEB FORM 和 ASP.NET MVC 它们两个没有本质区别,使用的都是ASP.NET WEB FORM 的管道处理模型,ASP.NET MVC 也是通过扩展 IHttpModule 和 IHttpHandler 来实现的,都是基于 ASP.NET 的 HttpApplication 的管道处理模型扩展的,在这个层面来说,它们是一样的。当然,大家不要抬杠,我说的本质区别都是在这个方面,不同意的勿喷。
有人会问,ASP.NET MVC 和 ASP.NET WEBAPI 它们会有什么不同吗?好像 WebAPi 能做的,WebMVC都可以完成,第一眼看上去,好像是这样,但是它们有着本质的不同。WebAPI 的处理管道是重新写过的,不是基于 HTTPApplication 管道扩展的。ASP.NET WEB API 类似专人做专事,它的管道处理模型更高效,并且有了 Restfull 的概念。当然,大家如何向了解更细的内容,就需要看源码了。或再说回来,到了 NET CORE 时代,二者又融合管道了。
二、MVC生命周期详述
1、我们既然要说 ASP.NET MVC的生命周期,为了给大家一个整体印象,俗话说,文不如图,我就贴一张图,按着箭头走,相信大家也会不能理解。

2、上图很简单,大家按着箭头走,也能理解的差不多。以下是按着我的理解,划分了4个模块。
(1)、路由模块
RouteBase 是对路由规则的抽象,也就是说,一个 RouteBase 对象,也就代表了一个条 路由规则。在 ASP.NET MVC 中,有一个唯一的子类实现就是 Route ,它同样也是路由规则的代表。我们有了路由规则,一定会把这个规则存放在一个地方,这个地方保存了很多路由规则,这个地方就是 RouteCollection,中文叫“路由集合”,因为这个集合里面包含的就是 RouteBase 对象。
RouteCollection 就是路由集合,用于保存路由规则对象,它的定义形式:
[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] public class RouteCollection : Collection { private class ReadLockDisposable : IDisposable { private ReaderWriterLockSlim _rwLock; public ReadLockDisposable(ReaderWriterLockSlim rwLock) { this._rwLock = rwLock; } void IDisposable.Dispose() { this._rwLock.ExitReadLock(); } } ...... RouteTable 就是路由表,其实它和 RouteCollection 是一样的。
public class RouteTable { private static RouteCollection _instance = new RouteCollection(); public static RouteCollection Routes { get { return RouteTable._instance; } } } 在ASP.NET MVC处理管线中的第一站就是路由模块。当请求到达路由模块后,ASP.NET MVC 框架就会根据 RouteTable 中配置的路由模板来匹配当前请求以获得对应的 Controller 和 Action 信息。具体的匹配过程就是有UrlRoutingModule(System.Web.Routing.UrlRoutingModule)来实现的。如果遇到一个匹配的规则,就会立刻跳出下面的配置。也就是说,配置过程是有顺序的,如果有一个匹配,后面就算有匹配的也不会执行的。
namespace System.Web.Routing { [TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] public class UrlRoutingModule : IHttpModule { private static readonly object _contextKey = new object(); private static readonly object _requestDataKey = new object(); private RouteCollection _routeCollection; public RouteCollection RouteCollection { get { if (this._routeCollection == null) { this._routeCollection = RouteTable.Routes; } return this._routeCollection; } set { this._routeCollection = value; } } protected virtual void Dispose() { } protected virtual void Init(HttpApplication application) { if (application.Context.Items[UrlRoutingModule._contextKey] != null) { return; } application.Context.Items[UrlRoutingModule._contextKey] = UrlRoutingModule._contextKey; application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpApplication httpApplication = (HttpApplication)sender; HttpContextBase context = new HttpContextWrapper(httpApplication.Context); this.PostResolveRequestCache(context); } [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")] public virtual void PostMapRequestHandler(HttpContextBase context) { } public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context); 第一步匹配路由规则 if (routeData == null) { return; } IRouteHandler routeHandler = routeData.RouteHandler; 第二步:如有匹配,就找到RouteHandler对象,该类型的实例是:MvcRouteHandler。 if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); } if (routeHandler is StopRoutingHandler) { return; } RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);第三步,根据 RouteHandler 对象,找到最终处理请求的 IHttpHandler 的对象,该类型是 MvcHandler if (httpHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (!(httpHandler is UrlAuthFailureHandler)) { context.RemapHandler(httpHandler);第四步,有找到的 IHttpHandler 处理请求。 return; } if (FormsAuthenticationModule.FormsAuthRequired) { UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); return; } throw new HttpException(401, SR.GetString("Assess_Denied_Description3")); } void IHttpModule.Dispose() { this.Dispose(); } void IHttpModule.Init(HttpApplication application) { this.Init(application); } } } (2)、Controller 创建模块
经过了路由模块,生成了 RouteData 路由数据,它包含了根据路由规则匹配的 Controller 和 Action。有了路由数据,需要有处理器来处理请求,这个任务就交给了 RouteData 的 RouteHandler 属性,它的类型是 IRouteHandler,它的值就是MvcRouteHandler,MvcRouteHandler 调用 GetHttpHandler 获取处理请求的 IHttpHandler 对象,在 MVC 框架中就是 MvcHandler,详细代码如下:
namespace System.Web.Mvc { /// Selects the controller that will handle an HTTP request. public class MvcHandler : IHttpAsyncHandler, IHttpHandler, IRequiresSessionState { private struct ProcessRequestState { internal IAsyncController AsyncController; internal IControllerFactory Factory; internal RequestContext RequestContext; internal void ReleaseController() { this.Factory.ReleaseController(this.AsyncController); } } [CompilerGenerated] [Serializable] private sealed class <>c { public static readonly MvcHandler.<>c <>9 = new MvcHandler.<>c(); public static BeginInvokeDelegate<>9__20_0; public static EndInvokeVoidDelegate<>9__20_1; public static Func, bool><>9__26_0; internal IAsyncResult b__20_0(AsyncCallback asyncCallback, object asyncState, MvcHandler.ProcessRequestState innerState) { IAsyncResult result; try { result = innerState.AsyncController.BeginExecute(innerState.RequestContext, asyncCallback, asyncState); } catch { innerState.ReleaseController(); throw; } return result; } internal void b__20_1(IAsyncResult asyncResult, MvcHandler.ProcessRequestState innerState) { try { innerState.AsyncController.EndExecute(asyncResult); } finally { innerState.ReleaseController(); } } internal bool b__26_0(KeyValuePair entry) { return entry.Value == UrlParameter.Optional; } } private static readonly object _processRequestTag = new object(); internal static readonly string MvcVersion = MvcHandler.GetMvcVersionString(); /// Contains the header name of the ASP.NET MVC version. public static readonly string MvcVersionHeaderName = "X-AspNetMvc-Version"; private ControllerBuilder _controllerBuilder; internal ControllerBuilder ControllerBuilder { get { if (this._controllerBuilder == null) { this._controllerBuilder = ControllerBuilder.Current; } return this._controllerBuilder; } set { this._controllerBuilder = value; } } /// Gets or sets a value that indicates whether the MVC response header is disabled. /// true if the MVC response header is disabled; otherwise, false. public static bool DisableMvcResponseHeader { get; set; } /// Gets a value that indicates whether another request can use the instance. /// true if the instance is reusable; otherwise, false. protected virtual bool IsReusable { get { return false; } } /// Gets the request context. /// The request context. public RequestContext RequestContext { get; private set; } /// Gets a value that indicates whether another request can use the instance. /// true if the instance is reusable; otherwise, false. bool IHttpHandler.IsReusable { get { return this.IsReusable; } } /// Initializes a new instance of the class. /// The request context. /// The parameter is null. public MvcHandler(RequestContext requestContext) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } this.RequestContext = requestContext; } /// Adds the version header by using the specified HTTP context. /// The HTTP context. protected internal virtual void AddVersionHeader(HttpContextBase httpContext) { if (!MvcHandler.DisableMvcResponseHeader) { httpContext.Response.AppendHeader(MvcHandler.MvcVersionHeaderName, MvcHandler.MvcVersion); } } /// Called by
相关内容
- C#中efcore-ShardingCore呈现“完美”分表_实用技巧_
- Asp.net Core 如何设置黑白名单(路由限制)_实用技巧_
- 详解.NET数据库连接池_实用技巧_
- Quartz.NET的具体使用_实用技巧_
- .NET5控制台程序使用EF连接MYSQL数据库的方法_实用技巧_
- .NET中创建对象的几种方式和对比_实用技巧_
- .net core 基于Hangfire+Mysql持久化实现定时任务配置方法_实用技巧_
- .Net Core 使用NLog记录日志到文件和数据库的操作方法_实用技巧_
- .NET Core中如何实现或使用对象池?_实用技巧_
- .NET Core授权失败自定义响应信息的操作方法_实用技巧_
点击排行
本栏推荐
