谈MVC运行机制,源码剖析
谈MVC整体运行机制:
首先我们在浏览器段输入网址:http://www.sina.com/news/society/1,回车。浏览器会通过DNS解析器,解析出域名的对应IP地址,通过IP地址连接到对应的主机的服务器。
连接服务器后,服务器首先会调用扩展程序ASPNET_ISAPI.dll进行处理,之后会调用这个程序集里的IsAPIRuntime类,创建一个HttpWorkRequest对象,内部存放有请求报文源信息.。
HttpWorkerRequest对象内部一览
接着执行HttpRuntime的ProcessRequest方法,将HttpWorkRequest作为参数创建HttpContext对象,HttpContext的Init方法会通过对象创建HttpResponse,HttpRequest,Session,Server等对象。
接着执行HttpApplicationFactory的Init方法:
1.确保网站第一次访问时调用了Global文件里的Application_Start方法;
2.获取Global文件里的类型作为网站的HttpApplication;
3.每次返回一个HttpApplication类或子类的对象;
a) 创建系统配置文件及用户配置的HttpModule对象,FrameWork4的系统配置文件中添加了一个HttpModule:UrlRoutingModule.循环调用Init方法,为app对象里面的某些方法事件注册方法(向请求管道里的事件注册用户的代码,完成AOP编程)
执行HttpApplication的ProcessRequest方法,内部执行“管道事件”.
当执行到执行第七个“管道事件”,创建一个MvcHanlder,存入HttpContent中
RouteData routeData = this.RouteCollection.GetRouteData(context);
1.判断浏览器URL是否有服务器文件对应,如果有,则停止方法,继续执行后面的“管道事件”,(因为js/css/jpg等不需要经过mvc处理);
2.根据url到路由表里查找匹配url规则的路由。
a) 遍历路由表(RouteCollection)里的所有路由,元素类型为Route,并调用每个Route对象的GetRouteData方法。
b) GetRouteData方法中创建了一个RouteData对象,并将Route里MvcRouteHandler对象传进去
i. RouteData data=new RouteData(this,this.RouteHandler);this就是Route对象,调用ProcessConstraints检查约束,如果URL不满足约束的话,直接返回Null,停止方法执行,最后将Route对象里的URL默认值和命名空间存入RouteData中,最后返回RouteData对象。
3..接着执行RequestContext requestContext =new RequestContext(context,routeData);创建MvcHandler,并将RequestContext存入。
IHttpHandle httpHandler=routeHandler.GetHttpHandler(requestContext);
a) 执行routeData.GetHttpHandler方法,获取一个MvcHandler对象
b) context.RemapHandler(httpHandler);
其实就是将MvcHandler存入了HttpContext对象。
当执行到第八个事件的时候:首先会检查HttpContext里的remapHanlder,发现不为空,所以不再根据url创建页面对象,直接略过,执行后面的事件。
接着调用MvcHandler的ProcessRequest方法:
1.创建被请求的Controll类的对象,并调用里面对应的Action方法;
2.找到视图引擎,创建对应的视图对象,视图引擎解析视图,生成Html代码。
接着获取控制器的名称:
1.string requiredString =this.RequestContext.RouteData.GetRequiredString(“controller”);
2.获取一个控制器工厂对象:
Factory =this.ControllerBuilder.GetControllerFactory();
3.通过工厂,创建被请求的控制器类对象。
Controller=factory.CreateController(this,RequestContext,requiredString);
4.调用控制器父类ControllerBase里的Excute方法
Controller.Excute(this,RequestContext);
4.1将上下文对象设置给ControllerContext(requestContext,this);
4.2 调用控制器里的Action方法
2.开始执行ViewResultBase的ExcuteResult方法,这个方法要做的是:找到视图引擎,找到视图,执行视图生成html代码。
a) 先检查是否传入指定的视图名称,如果没有传入,则取Action方法的名字作为待会要读取的【视图名字】
If(string.IsNullOrEmpty(this.ViewName)).this.ViewName=Context.RouteData.GetRequiredString(“action”);
b) 找到对应的视图引擎
ViewEngineResult result=this.FindView(context,base.ViewName,this.MasterName);
c) 找到了RazorViewEngine对象之后,将会:
i. 调用试图引擎的FindView方法,但这个方法在RazorViewEngine类中没有,而是在父类中定义继承关系:
RazorViewEngine->BuildManagerViewEngine->VirtualPathProviderViewEngine
获取控制器名称,视图的路径:
String controllerName=controllerContext.RouteData.GetRequiredString(“controller”);
String virePath=GetPath(controllerContext,ViewLocationFormats,AreaViewLocationFormats,”ViewLocationFormats”,viewName,controllerName,_cacheKeyPrefic_View,useCache,out viewLocationSearched);
同时,还获得了母板页/布局页的路径
另一种情况:
Return new ViewEngineResult(CreateView(controllerContext,viewPath,masterPath),this);
返回ViewEngineResult中就包含了这个RazorView对象了。
3.最终返回ViewEngineResult
4.获取返回的ViewEngineResult里的View对象,然后调用它的Render方法来生成html代码并写入Response中。
最后生成Html代码