当前位置: 首页 > news >正文

平台类网站制作公司站长seo

平台类网站制作公司,站长seo,深圳手机网站开发,昆明网站建设注意事项开篇#xff1a;上一篇我们了解了在WebForm模式下一个Page页面的生命周期#xff0c;它经历了初始化Init、加载Load以及呈现Render三个重要阶段#xff0c;其中构造了页面控件树#xff0c;并对页面控件树进行了大量的递归操作#xff0c;最后将与模板结合生成的HTML返回给…开篇上一篇我们了解了在WebForm模式下一个Page页面的生命周期它经历了初始化Init、加载Load以及呈现Render三个重要阶段其中构造了页面控件树并对页面控件树进行了大量的递归操作最后将与模板结合生成的HTML返回给了浏览器。那么在ASP.NET MVC模式下一个页面的生命周期又经历了哪些步凑呢别急本篇漫漫道来 1Part 1前奏 2Part 2核心 3Part 3管道 4Part 4WebForm页面生命周期 5Part 5ASP.NET MVC请求处理流程 一、开放的ASP.NET MVC代码 2009年Microsoft推出了ASP.NET MVC也将ASP.NET MVC项目作为开源项目推送到了开源社区中至今时间也过去快6年了ASP.NET MVC已经到了5.0的版本阶段了。我们看到ASP.NET MVC从一个不完整的小孩长成一个日渐成熟的巨人我们可以从开源社区找到ASP.NET MVC的源码相比之前我们需要Reflector进行反编译查看这次则轻松得多。 这里我们选择ASP.NET MVC 4的源码作为分析对象我已经将其上传到了网盘中你可以通过下面这个地址进行下载 传送门http://pan.baidu.com/s/1bnF8ZPt 下载完成后打开ASP.NET MVC 4的源代码你会看到如下解决方案这里我们主要关注System.Web.Mvc这个类库项目 二、从MvcHandler.ProcessRequest开始 从Part 3中我们知道了在请求处理管道中的第7个事件生成了MvcHandler在第11和第12个事件之间调用了MvcHandler的ProcessRequest方法开始了ASP.NET MVC的处理响应之旅。那么我们就从MvcHandler的ProcessRequest方法开始查看一个ASP.NET MVC页面是如何加载出来一个HTML页的 1Controller的激活 ①借助HttpConetxtWrapper封装HttpContext protected virtual void ProcessRequest(HttpContext httpContext){HttpContextBase httpContextBase new HttpContextWrapper(httpContext);ProcessRequest(httpContextBase);} 可以看出这里通过了一个基于包装器又称装饰者模式实现的一个HttpContextWrapper类对HttpContext进行了一个封装并调用重载的另一个ProcessRequest方法进行继续处理。 PS有关ASP.NET MVC中HttpContext, HttpContextBase, HttpContextWrapper三者之间的联系请参考http://blog.csdn.net/sundacheng1989/article/details/10551091 ②控制器工厂根据URL创建控制器 protected internal virtual void ProcessRequest(HttpContextBase httpContext){IController controller;IControllerFactory factory;ProcessRequestInit(httpContext, out controller, out factory);try{controller.Execute(RequestContext);}finally{factory.ReleaseController(controller);}} 可以看出这里通过调用ProcessRequestInit方法将上下文对象传入进行处理然后返回生成的控制器实例以及控制器工厂。因此我们转入ProcessRequestInit方法看看 private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory){......string controllerName RequestContext.RouteData.GetRequiredString(controller);factory ControllerBuilder.GetControllerFactory();controller factory.CreateController(RequestContext, controllerName);......} 在这个方法中首先根据RouteData路由数据取得要请求的Controller名称然后取得ControllerFactory控制器工厂对象通过ControllerFactory来创建指定名称的控制器最后将控制器作为out参数传递出去。 ③调用控制器的Execute方法进入Action 具体实现了IController接口的Controller对象通过调用Excute方法开始执行具体的Action那么Action究竟又是怎样被触发的呢 public interface IController{void Execute(RequestContext requestContext);} 2Action的触发 ①从ControllerBase的Excute方法开始  public abstract class ControllerBase : IController{protected virtual void Execute(RequestContext requestContext){if (requestContext null){throw new ArgumentNullException(requestContext);}if (requestContext.HttpContext null){throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, requestContext);}VerifyExecuteCalledOnce();Initialize(requestContext);using (ScopeStorage.CreateTransientScope()){ExecuteCore();}}// 抽象方法-让Controller去具体实现protected abstract void ExecuteCore();} 首先Controller并没有实现IController接口而是Controller的基类ControllerBase实现了IController接口然后ControllerBase中定义了一个抽象方法ExcuteCore让其子类去具体执行这里主要是让Controller类对象执行这个方法。 ②根据URL获取Action名称并准备触发Action public abstract class Controller : ControllerBase, IActionFilter, IAuthenticationFilter, IAuthorizationFilter, IDisposable, IExceptionFilter, IResultFilter, IAsyncController, IAsyncManagerContainer{protected override void ExecuteCore(){PossiblyLoadTempData();try{string actionName GetActionName(RouteData);if (!ActionInvoker.InvokeAction(ControllerContext, actionName)){HandleUnknownAction(actionName);}}finally{PossiblySaveTempData();}}} 首先通过路由数据获取Action名称例如请求URL为:http://xxx.com/Home/Index这里获取的Action名称即为Index。然后通过ActionInvoker.InvokeAction去执行具体的Action。那么问题来了这个ActionInvoker又是啥东东我们先看看这个接口的定义 public interface IActionInvoker{bool InvokeAction(ControllerContext controllerContext, string actionName);} 通过查阅资料我们发现原来是一个叫做ControllerActionInvoker的类实现了IActionInvoker接口那么我们就去看看这个ControllerActionInvoker类吧。 ③获取Controller与Action的描述信息和过滤器信息 public virtual bool InvokeAction(ControllerContext controllerContext, string actionName){......ControllerDescriptor controllerDescriptor GetControllerDescriptor(controllerContext);ActionDescriptor actionDescriptor FindAction(controllerContext, controllerDescriptor, actionName);if (actionDescriptor ! null){FilterInfo filterInfo GetFilters(controllerContext, actionDescriptor);......} ......} 看到这里也许会有人问什么是描述信息那么看到我们在开发中经常给Controller或者Action添加的Attribute信息也许就不会感到陌生了例如我们给某个名为Index的Action添加了[HttpPost]或者[HttpGet]特性在请求时需要通过HTTP报文请求方式来区分这两个Action。 那么什么又是过滤器信息首先过滤器涉及到一个叫做AOP面向切面编程的概念我们可以通过前面的请求处理管道进行理解虽然我们的ASP.NET页面请求处理部分只是其中一小部分但是在这部分执行之前还经历了许多事件在这之后又经历了许多事件而这些事件都是可以自定义逻辑的它们都可以叫做过滤器。ASP.NET MVC默认为我们提供了四种类型的过滤器Filter如下图所示 PS对过滤器不熟悉的朋友可以看看我的另一篇对ASP.NET MVC基础知识中的过滤器Filter的介绍http://www.cnblogs.com/edisonchou/p/3932640.html ④获取参数信息并开始真正执行ActionFilter-Action-Filter public virtual bool InvokeAction(ControllerContext controllerContext, string actionName){......IDictionarystring, object parameters GetParameterValues(controllerContext, actionDescriptor);ActionExecutedContext postActionContext InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);......} 通过上面所获取的各种描述信息与过滤器信息找到Action并获取所需的参数然后调用InvokeActionMethodWithFilters方法执行Action。因此再转到InvokeActionMethodWithFilters方法看看 protected virtual ActionExecutedContext InvokeActionMethodWithFilters(ControllerContext controllerContext, IListIActionFilter filters, ActionDescriptor actionDescriptor, IDictionarystring, object parameters){ActionExecutingContext preContext new ActionExecutingContext(controllerContext, actionDescriptor, parameters);FuncActionExecutedContext continuation () new ActionExecutedContext(controllerContext, actionDescriptor, false /* canceled */, null /* exception */){Result InvokeActionMethod(controllerContext, actionDescriptor, parameters)};FuncActionExecutedContext thunk filters.Reverse().Aggregate(continuation,(next, filter) () InvokeActionMethodFilter(filter, preContext, next));return thunk();} 在这个方法中首先将上下文对象、描述信息、参数信息传入InvokeActionMethod方法中得到了一个Result对象。这个Result对象又是什么转到定义一看原来不就是我们在开发中经常返回的ActionResult类型吗 public ActionResult Result{get { return _result ?? EmptyResult.Instance; }set { _result value; }} 那么在InvokeActionMethod方法中又是如何返回Result的呢再次转到定义看看 protected virtual ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionarystring, object parameters){object returnValue actionDescriptor.Execute(controllerContext, parameters);ActionResult result CreateActionResult(controllerContext, actionDescriptor, returnValue);return result;} 在这个方法中首先执行了指定的Action然后获得了一个returnValue返回值通过传入返回值创建具体类型的ActionResult作为方法的返回值。这里需要注意的是ActionResult是一个抽象类像什么JsonResult、EmptyResult、ViewResult等都是其子类而这里的CreateActionResult就是要创建其具体子类的实例并返回。 现在将目光返回到InvokeActionMethodWithFilters方法中看到代码最后声明了一个委托thunk它是过滤器结合经过反转之后再合并之前声明的委托continuation之后的一个新委托它所持有的委托链顺序会协调一致目的是为了完成AOP的效果比如首先要执行Action执行之前的过滤器才能执行Action方法。 ⑤ActionResult闪亮登场Filter-Result public virtual bool InvokeAction(ControllerContext controllerContext, string actionName){......InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, challengeContext.Result ?? postActionContext.Result);......} 现在回到InvokeAction这个主方法中刚刚执行完Action之后将结果都保存在了postActionContext中的Result中现在继续执行过滤器比如可以对刚刚的Action结果进行一些处理目的也是为了完成AOP的效果比如执行完Action之后必须要执行Action结束后的过滤器业务逻辑方法。那么这里又是进行了什么操作呢转到InvokeActionResultWithFilters方法中去看看 private ResultExecutedContext InvokeActionResultFilterRecursive(IListIResultFilter filters, int filterIndex, ResultExecutingContext preContext, ControllerContext controllerContext, ActionResult actionResult){......if (filterIndex filters.Count - 1){InvokeActionResult(controllerContext, actionResult);return new ResultExecutedContext(controllerContext, actionResult, canceled: false, exception: null);} IResultFilter filter filters[filterIndex];filter.OnResultExecuting(preContext); ......int nextFilterIndex filterIndex 1;postContext InvokeActionResultFilterRecursive(filters, nextFilterIndex, preContext, controllerContext, actionResult);......} 首先判断过滤器执行的序号是否已经到了最后如果不是则继续递归执行本方法调用过滤器这里对应的过滤器是OnResultExecuting事件即在Result被生成时之前进行触发。如果到了最后则开始生成最终的ActionResult。看看这个InvokeActionResult方法它是一个虚方法。 protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult){actionResult.ExecuteResult(controllerContext);} 3View的呈现 我们知道ActionResult是一个抽象类那么这个InvokeActionResult应该是由其之类来实现。于是我们找到ViewResult但是其并未直接继承于ActionResult再找到其父类ViewResultBase它则继承了ActionResult。于是我们来查看它的ExecuteResult方法 ①约定大于配置的缘故 public override void ExecuteResult(ControllerContext context){......if (String.IsNullOrEmpty(ViewName)){ViewName context.RouteData.GetRequiredString(action);}......} 我们在日常开发中总是被告知约定大于配置View中的名字必须与Controller中Action的名字一致。在这了我们知道了原因可以看出这里就是国通URL来取得ViewName然后去查找View的。 ②找到ViewEngine视图引擎并获取ViewEngineResult 首先我们了解一下什么是ViewEngine视图引擎我们在ASP.NET MVC开发中一般会有两个选择一个是aspx视图引擎另一个是ASP.NET MVC 3.0推出的Razor视图引擎。Razor视图引擎在减少代码冗余、增强代码可读性和Visual Studio智能感知方面都有着突出的优势。因此Razor一经推出就深受广大ASP.Net开发者的喜爱。 public override void ExecuteResult(ControllerContext context){......ViewEngineResult result null;if (View null){result FindView(context);View result.View;}...... } 这里通过FindView方法获取到具体的View对象而FindView又是ViewResultBase的一个抽象方法。这时我们需要到ViewResult中去看看这个FindView方法。 protected override ViewEngineResult FindView(ControllerContext context){ViewEngineResult result ViewEngineCollection.FindView(context, ViewName, MasterName);if (result.View ! null){return result;}......} 这里通过在ViewEngineCollection视图引擎集合中调用FindView方法返回一个ViewEngineResult对象而View则作为属性存在于这个ViewEngineResult对象之中。 ③加载ViewData/TempData等数据生成ViewContext protected override ViewEngineResult FindView(ControllerContext context){......TextWriter writer context.HttpContext.Response.Output;ViewContext viewContext new ViewContext(context, View, ViewData, TempData, writer);......} 这里开始加载ViewData、TempData等数据生成ViewContext可以在ViewContext的构造函数中看到如下代码 public ViewContext(ControllerContext controllerContext, IView view, ViewDataDictionary viewData, TempDataDictionary tempData, TextWriter writer): base(controllerContext){if (controllerContext null){throw new ArgumentNullException(controllerContext);}if (view null){throw new ArgumentNullException(view);}if (viewData null){throw new ArgumentNullException(viewData);}if (tempData null){throw new ArgumentNullException(tempData);}if (writer null){throw new ArgumentNullException(writer);}View view;ViewData viewData;Writer writer;TempData tempData;} 现在知道我们在Action方法中定义的那些ViewData或者TempData是在哪里被存入上下文了吧 ④开始RenderHTML页面的呈现 protected override ViewEngineResult FindView(ControllerContext context){......View.Render(viewContext, writer);......} ViewContext上下文对象已生成好TextWriter已经拿到现在就开始对View进行正式的呈现了也就是返回给浏览器端请求的HTML。由于这里View对象是一个实现了IView接口的类对象于是我们找到RazorView但是它并未直接实现IView接口于是我们找到它的父类BuildManagerCompiledView  public abstract class BuildManagerCompiledView : IView{public virtual void Render(ViewContext viewContext, TextWriter writer){if (viewContext null){throw new ArgumentNullException(viewContext);}object instance null;Type type BuildManager.GetCompiledType(ViewPath);if (type ! null){instance ViewPageActivator.Create(_controllerContext, type);}if (instance null){throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,MvcResources.CshtmlView_ViewCouldNotBeCreated,ViewPath));}RenderView(viewContext, writer, instance);}} 首先通过ViewPath获取View的类型Type这里也是通过BuildManger来完成的每个cshtml都会被asp.net编译成一个类。然后通过反射生成了View的具体实例。最后通过RendView方法进行下一步的呈现工作。RenderView是一个抽象方法具体实现是在RazorView类或WebFormView类中。 protected override void RenderView(ViewContext viewContext, TextWriter writer, object instance){if (writer null){throw new ArgumentNullException(writer);}WebViewPage webViewPage instance as WebViewPage;if (webViewPage null){throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture,MvcResources.CshtmlView_WrongViewBase,ViewPath));}webViewPage.OverridenLayoutPath LayoutPath;webViewPage.VirtualPath ViewPath;webViewPage.ViewContext viewContext;webViewPage.ViewData viewContext.ViewData;webViewPage.InitHelpers();if (VirtualPathFactory ! null){webViewPage.VirtualPathFactory VirtualPathFactory;}if (DisplayModeProvider ! null){webViewPage.DisplayModeProvider DisplayModeProvider;}WebPageRenderingBase startPage null;if (RunViewStartPages){startPage StartPageLookup(webViewPage, RazorViewEngine.ViewStartFileName, ViewStartFileExtensions);}webViewPage.ExecutePageHierarchy(new WebPageContext(context: viewContext.HttpContext, page: null, model: null), writer, startPage);} 在此方法中首先将传递过来的实例转换成了一个WebViewPage类的实例然后将ViewContext、ViewData等数据赋给WebViewPage实例作为属性以便在View中获取。然后如果有开始页则先执行开始页。最后将HttpContext、Page与Model对象封装为一个WebPageContext对象传入ExecutePageHierarchy方法中进行执行页面的渲染。 首先我们从字面上来看Hierarchy代表层次那么方法名的意思大概是根据层次执行页面。那么什么是页面的层次 在执行ExecutePageHierachy这个方法来渲染View时这个方法里面要完成相当多的工作主要是ViewStart的执行和Layout的执行。这里的困难之处在于对于有Layout的页面来说Layout的内容是先输出的然后是RenderBody内的内容最后还是Layout的内容。如果仅仅是这样的话只要初始化一个TextWriter按部就班的往里面写东西就可以了但是实际上Layout并不能首先执行而应该是View的代码先执行这样的话View就有可能进行必要的初始化供Layout使用。例如我们有如下的一个View {ViewBag.Title Code in View;Layout _LayoutPage1.cshtml; } 这个Layout的内容如下 { Layout ~/Views/Shared/_Layout.cshtml;ViewBag.ToView Data from Layout; } divData In View: ViewBag.Title /div divRenderBody(); /div 这样可以在页面显示Code in View字样。 但是反过来如果试图在View中显示在Layout里面的Data from Layout 则是行不通的,什么也不会被显示。所以RenderBody是先于Layout中其他代码执行的这种Layout的结构称为 Page Hierachy。 在这样的代码执行顺序下还要实现文本输出的顺序因此asp.net mvc这里的实现中就使用了栈这个栈是OutputStack里面压入了TextWriter。注意到这只是一个页面的处理过程一个页面之中还会有Partial View 和 Action等这些的处理方式都是一样的因此还需要一个栈来记录处理到了哪个子页面因此还有一个栈称之为TemplateStack里面压入的是PageContextPageContext维护了view的必要信息比如Model之类的当然也包括上面提到的OutputStack。有了上面的基本信息下面看代码先看入口点 public void ExecutePageHierarchy(WebPageContext pageContext, TextWriter writer, WebPageRenderingBase startPage) {PushContext(pageContext, writer);if (startPage ! null) {if (startPage ! this) {var startPageContext Util.CreateNestedPageContextobject(parentContext: pageContext, pageData: null, model: null, isLayoutPage: false);startPageContext.Page startPage;startPage.PageContext startPageContext;}startPage.ExecutePageHierarchy();}else {ExecutePageHierarchy();}PopContext();} 这个方法中第一步首先将pageContext入栈PushContext public void PushContext(WebPageContext pageContext, TextWriter writer){_currentWriter writer;PageContext pageContext;pageContext.Page this;InitializePage();// Create a temporary writer_tempWriter new StringWriter(CultureInfo.InvariantCulture);// Render the page into itOutputStack.Push(_tempWriter);SectionWritersStack.Push(new Dictionarystring, SectionWriter(StringComparer.OrdinalIgnoreCase));// If the body is defined in the ViewData, remove it and store it on the instance// so that it wont affect rendering of partial pages when they call VerifyRenderedBodyOrSectionsif (PageContext.BodyAction ! null){_body PageContext.BodyAction;PageContext.BodyAction null;}} 第二步判断是否存在ViewStart文件如果有就执行startPage.ExecutePageHierachy()。如果不存在则直接执行ExecutePageHierachy()。 public override void ExecutePageHierarchy(){......TemplateStack.Push(Context, this);try{// Execute the developer-written code of the WebPageExecute();}finally{TemplateStack.Pop(Context);} } 这个方法就是将context压栈然后执行相应的view的代码然后出栈。有了这些出入栈的操作可以保证View的代码也就是Execute的时候的writer是正确的。Execute中的方法除去PartialViewAction之类的最终调用的是WebPageBase中的WriteLiteral方法 public override void WriteLiteral(object value){Output.Write(value);} 这里的Output属性是 public TextWriter Output{get { return OutputStack.Peek(); }} 在调用了Excute方法后页面上的HTML内容基本输出完毕至此View就渲染完毕了。 第三步pageContext出栈主要是栈中的元素的清理工作。 三、一图胜千言总体上概览 参考资料 致谢本文参阅了大量园友的相关文章向以下文章作者表示感谢 1Darren Ji《ASP.NET MVC请求处理管道声明周期的19个关键环节》http://www.cnblogs.com/darrenji/p/3795661.html 2初心不可忘《综述ASP.NET MVC请求处理管道》http://www.cnblogs.com/luguobin/archive/2013/03/15/2962458.html 3学而不思则罔《ASP.NET Routing与MVC之二请求如何激活Controller与Action》http://www.cnblogs.com/acejason/p/3886968.html 4王承伟《ASP.NET MVC请求原理与源码分析》http://bbs.itheima.com/thread-134340-1-1.html 5Ivony《通过源代码研究ASP.NET MVC中的Conroller和View》http://www.cnblogs.com/Ivony/archive/2010/11/13/aspnet-mvc-by-source-1.html 6痞子一毛《ASP.NET MVC请求处理图解》http://www.cnblogs.com/piziyimao/archive/2013/02/27/2935969.html 7蒋金楠《ASP.NET MVC中的View是如何被呈现出来的》http://www.cnblogs.com/artech/archive/2012/08/22/view-engine-01.html 8yinzixin《深入ASP.NET MVC之七ActionResult的执行》http://www.cnblogs.com/yinzixin/archive/2012/12/05/2799459.html 一篇好文值得阅读
http://www.zqtcl.cn/news/701225/

相关文章:

  • 中英文 微信网站 怎么做网站的建站公司
  • 苏州网站建设新手去哪找做塑料的网站
  • 莱芜网站建设电话瓦房店网站建设
  • 视频网站app怎么做的天津seo标准
  • 建立音乐网站wordpress 安装文件名
  • 龙华营销型网站制作企业网站模板源代码下载
  • 山东城乡建设厅网站哪有做网站公司
  • 建设网站是否等于开展网络营销用wordPress搭建图片库
  • 泗阳做网站的外贸公司网站搭建
  • 做汽车保养的网站上商业招商网站
  • 如何进网站帝国cms调用网站名称
  • 瑞金网站建设推广合肥瑶海区地图
  • 静态网站建设国内免费域名
  • 网站建设设计公司电子商务网站开发与管理
  • 手机网站制作设计做国际网站有什么需要注意的
  • 机构网站源码如何分析一个网站
  • 免费营销软件网站网站建设与规划实训总结
  • 网站深度功能建筑人才网市场
  • 学校网站建设的意义和应用服务平台管理系统
  • 网站内容规划要包括什么内容wordpress5.2 php版本
  • 山西建设部网站超值的镇江网站建设
  • 做淘宝要网站网站推广外链怎么做
  • 深圳做网站推广哪家好自建网站优缺点
  • 网站建设询价函什么网站可以做会计题目
  • 电脑网站视频怎么下载珠海免费网站制作
  • wordpress menu icon咸阳seo
  • php制作网站网站开发与客户沟通
  • 百度网站建设平台微盟微商城官网
  • 三明网站seo上海中学分数线
  • 青岛谷歌网站建设网站建站公司排名