ASP.NET MVC流程解说
2015-10-02 14:40
260 查看
开始想这个标题时,,很忧郁什么标题将得到更好的叫什么,最后确定的解释,虽然稍0基金会,但是,这个概念是非常。我想出了一个相当的价格值的。
,開始。
1、MVC的基本开发流程
2、webform和MVC的选择
3、MVC的内部过程
MVC使用vs2010进行开发时(这里介绍的是MVC2),首先须要选在一个模板,然后vs2010会帮忙创建好相应的文件夹结构。
每一个文件夹的基本功能:
Content:主要用于描写叙述css之类的资源
Controllers:主要就是controller的存放位置。创建controller时。都是须要在该文件夹创建的。
Models:主要就是entity的详细位置。以及跟entity相关的操作类
Scripts:javascript脚本存放的位置
Views:该部分主要是放置view显示部分的
Global.asax:眼下来看,该部分主要就是路由设置
Web.config:该配置文件而已
从开发的流程方面来看,MVC的开发方式,或者说思考的方式出现了变化,在MVC其中。须要理解一个重要的点是:
Controller才是系统的中心,一切环绕Controller展开。
Model:所谓模型,能够理解为数据,这个数据能够是数据库中相应的表中的数据,这样的数据是仅仅有属性,而没有动作的。这样的数据通常也被称之为Entity,即实体,除了这样的数据之外。MODLE起始还要包含Interface,这些接口的目标是提供能够控制Entity的接口标准,然后在提供实现的载体,通常我们称之为Mock类,为了方便,可能我们还会在Model其中创建各种factory。从而简化对象的创建。
Controller:这个部分就是核心了,事实上所谓核心,是说所有的处理,所有环绕着Controller展开,它的主要工作是訪问model,获取数据后,将參数转发给view,然后让view表现出来。
在这里主要完毕的工作有两点:
1、在client訪问一个页面后。须要跳转到Controller相应的action中去。然后在action中处理相应的view显示出来。
2、完毕客户的表单提交对应处理,也就是Form表单处理。(还记得之前讲过,对于HTML而言。仅仅有Form表单实现了client的信息发送给服务端。然后由服务端处理相关的对应,由于MVC的设计目标就是放弃了微软原有的server控件,因此一切回归原始,採用HTML的form表单方式实现提交和相关的控制处理。)
View:顾名思义,该部分就是现实的部分,这个部分须要时刻记住的是,这个view尽管也是aspx的页面,可是已经发生了根本性的变化,不再有所谓的codebeind代码了。这个view的全部变成将採用混合式的变成。你会注意到这个部分的变成变为HTML与C#的混合。会出现非常多的<%%><%=%>类似的代码。
非常多人起始对这个部分有不同的开发。混合代码对于分层不利。可是在MVC中,由于不涉及逻辑,所以view的表现变得简单。混合编程会变为能够接受的处理方式。
另外,这样的方式带来的优点是,美工能够介入了。他们的改动对于程序猿来说。没有什么特别,也是非常easy直接引入的。
带来的坏处是Gridview这样的强大的server控件被丢弃了。
尽管是这样。可是我个人认为。这是回到了web开发的本质。
他的思想,与JSP,PHP等等变为一致。
Golabal.asax:路由表。这个部分就是所谓的全局路由表。在MVC框架中。之所以实现了MVC功能,一个重要的概念是路由表,该部分实现了地址訪问的动态。不再提供详细页面的訪问模式。
注意:给我的感觉是,记住在view文件夹和model文件夹中。加入子文件夹,每一个controller相应的view,都是一个文件夹下的view。
这个是MVC框架查找时自己主动搜索的。
我这里仅仅是想谈谈两者的思想出发点的区别:
webform模式。这个模式的思维基础,是微软在桌面开发中取得了前所未有的成功。这些成功,微软希望拷贝到网络开发中,何为form。就是窗体开发。这样的框架的逻辑是所见即所得+事件处理,微软希望可以将web实现为桌面开发的模式。可是网络开发的基础是HTML和HTTP协议,这两个部分带来的问题是HTML表现元素有限,而且仅仅可以通过form与后台server通信。另外,HTTP协议无状态,无法实现消息机制,为了解决这些问题,微软创造了新的开发模式,引入ASP.NETserver控件,实现了丰富的控件。通过postback回传机制,实现了事件模型,通过codebehind技术实现web页面与C#代码的分离。上述技术。的确非常成功,也确实非常大程度上简化了web的开发。可是随着发展,带来了问题,就是webform的开发基础是页面化的。这样的思维模式是说你开一个页面,然后在这个页面写响应事件。可是这样的模式对于频繁变化的web程序缺乏良好的复用性。而且,前端人员开发的界面。往往在合成时,须要重做,这是微软自己创造的困难。这是一种以Page为中心的开发思想。
MVC模式,这个模式的思维基础。是分工清晰,以Controller为核心。在开发时能够先做model再做Controller。最后做view,通过使用demoview实现。最后再替换美工的view。这样的模式变成了以数据为中心的开发思想。最大的优点是,这样的模式中每一个部分都能够灵活复用,最大限度的实现如今的各种网络须要。比方互联网和移动互联网。并且。其它的变成语言。在思想方面也基本採用这样的模式。这样的模式终于被时间证明。成为了标准思考方式和开发方式。微软提倡的桌面化开发,渐渐退却往日之光芒。
尝试解说清楚MVC的基本运转流程。
MVC的主体过程:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZG9uZ2Rvbmdkb25nSkw=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast"border="0">
问题:
1、浏览器请求的地址,并非详细的某个页面,如1234.aspx页面。而是controller/action方法。这是怎样做到的?
2、Controller被訪问到以后。怎样找到详细的view进行返回的?
我个人的理解就是回答了上述的问题,也就解释清楚了MVC的基本框架。
第一个问题,浏览器请求地址的问题。MVC之所以可以找到详细的Controller是由于有一个route组件。实现了路由处理的功能。将请求转化为Controller的详细方法。须要注意该组件竟然是个独立组件。
Routing的作用:
1、解析URL,识别其中的參数
2、解析之后。调用详细的controller和action
比方首页地址是:localhost/home/index
我们发现訪问上面的地址,
最后会传递给HomeController中名为index的action(即HomeController类中的index方法).
当然server端不会自己去实现这个功能,
关键点就是在Global.asax.cs文件里的下列代码:
回来看我们的Url:localhost/home/index
localhost是域名,
所以首先要去掉域名部分:home/index
相应了上面代码中的这样的URL结构:{controller}/{action}/{id}
由于我们建立了这样的Url结构的识别规则,
所以可以识别出Controller是home,action是index,id没有则为默认值"".
上述功能之所以可以实现,关键在MapRoute方法。尽管MapRoute方法是RouteCollection对象的方法,可是却被放置在System.Web.Mvc程序集中,
假设你的程序仅仅引用了System.Web.Routing,
那么RouteCollection对象是不会有MapRoute方法的.
可是假设你同又引用了System.Web.Mvc,
则在mvc的dll中为RouteCollection对象加入了扩展方法:
RouteCollection是一个集合,他的每一项应该是一个Route对象.
可是我们使用MapRoute时并没有创建这个对象,
这是由于当我们将MapRoute方法须要的參数传入时,
在方法内部会依据參数创建一个Route对象:
上面就是MapRoute方法的实现,
至于在创建Route对象时第二个參数是一个MvcRouteHandler,
它是一个实现了IRouteHandler接口的类.IRouteHandler十分简单仅仅有一个方法:
參数是一个RequestContext
类实例,
这个类的结构也非常easy:
当中的一个属性RouteData就包括了Routing依据Url识别出来各种參数的值,
当中就有Controller和Action的值.
归根结底,ASP.NETMVC最后还是使用HttpHandler处理请求.ASP.NETMVC定义了自己的实现了IHttpHandler接口的Handler:MvcHandler,
由于MvcRouteHandler的GetHttpHandler方法最后返回的就是MvcHandler.
MvcHandler的构造函数须要传入RequestContext
对象,
也就是传入了全部的全部须要的数据,
所以最后能够找到相应的Controller和Action,
已经各种參数.
(引用參考:/article/4677249.html)
(引用參考:/article/4677250.html)
第二个问题:Controller找到了,Action也找到了。此时怎样哪?
以下分层次的总结Controller处理流程:
1.页面处理流程
发送请求–>UrlRoutingModule捕获请求–>MvcRouteHandler.GetHttpHandler()–>MvcHandler.ProcessRequest()
2.MvcHandler.ProcessRequest()处理流程:
使用工厂方法获取详细的Controller–>Controller.Execute()–>
释放Controller对象
3.Controller.Execute()处理流程
获取Action–>
调用Action方法获取返回的ActionResult–>
调用ActionResult.ExecuteResult()方法
4.ActionResult.ExecuteResult()处理流程
获取IView对象->
依据IView对象中的页面路径获取Page类->
调用IView.RenderView()方法(内部调用Page.RenderView方法)
通过对MVC源码的分析,我们了解到Controller对象的职责是传递数据,获取View对象(实现了IView接口的类),通知View对象显示.View对象的作用是显示.尽管显示的方法RenderView()是由Controller调用的,可是Controller不过一个"指挥官"的作用,
详细的显示逻辑仍然在View对象中.须要注意IView接口与详细的ViewPage之间的联系.在Controller和View之间还存在着IView对象.对于ASP.NET程序提供了WebFormView对象实现了IView接口.WebFormView负责依据虚拟文件夹获取详细的Page类,然后调用Page.RenderView().
引用參考:(Http://www.cnblogs.com/zhangziqiu/archive/2009/03/11/Aspnet-MVC-3.html)
说到这里。相信非常多人開始似乎明确了,又似乎不明确了,以下我做进一步的解说,先看一下。通常Controller的实现例如以下:
先看看关键类ActionResult。这个返回值。体现了微软精心设计。为什么做这么个类,事实上本质而言,微软希望这个action能够返回很多其它内容,而不不过view。
这里我们主要解说viewResult的作用。
在ASP.NETMVC中,ViewResult用的最多。Controller有一个View方法,它来实例化一个ViewResult对象,并返回。
以下是View方法:
ViewResult类的ExecuteResult方法的详细參考例如以下:
那么怎样FindView哪?详细例如以下:
rotectedoverrideViewEngineResultFindView(ControllerContextcontext){
ViewEngineResultresult=ViewEngineCollection.FindView(context,ViewName,MasterName);
if(result.View!=
null){
returnresult;
}
//weneedtogenerateanexceptioncontainingallthelocationswesearched
StringBuilderlocationsText=
newStringBuilder();
foreach(stringlocation
inresult.SearchedLocations){
locationsText.AppendLine();
locationsText.Append(location);
}
throw
newInvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
MvcResources.Common_ViewNotFound,ViewName,locationsText));
}
从ViewResult类的FindView方法中,得知ViewEngineResult是通过ViewEngineCollection的FindView得到的。而ViewEngineCollection正是ViewEngines的静态属性Engines,Engines返回一个仅仅有一个WebFormViewEngine类型实例的一个集合。所以。ViewEngineResult会是调用WebFormViewEngine类的FindView方法返回的结果。
假设ViewEngins的静态属性Engines有多个ViewEngine提供。那么就依次遍历它们直到找到第一个不为空的ViewEngineResult为止。这样我们就能够在同一个MVC站点中使用多种视图引擎了。
静态类ViewEngines的描写叙述例如以下:
从上述样例能够看出,起始微软为我们提供了两个ViewEngine,WebFormViewEngine和RazorViewEngine,WebFormViewEngine相应的是ASPX界面,RazorViewEngine相应的是.cshtml/.vbhtml引擎
此外,这里有一个隐藏非常深的概念,似乎非常多书都没讲清楚。每个引擎都会相应一个view。作为页面渲染使用。对于viewengine做进一步的解释,就是说,为什么一个view其中的<%%>之类的界面元素最后能够变成html。就是这些引擎在起作用。他们的内部实现,能够提供类似正則表達式或者是页面parsing的方法,完毕页面字符串解析。从而转换为相应的html,再response给client浏览器。
微软提供的两种viewengine和view例如以下:
RazorViewEngine和Razorview
(參考引用:http://www.cnblogs.com/artech/archive/2012/09/05/razor-view-engine-02.html)
WebformViewengine和Webformview
通过上边的讲述。主要的概念已经讲清楚了,假设希望实现自己的viewengine,能够查看一下微软參考实现是怎样做到的,然后我们就能够防治自己的viewengine了。这里便须要进一步说明的是。为什么MVC须要viewengine。而WEBFORM不须要,是由于,微软的webform是直接通过IHttphandler处理了,也就是说ASP.NETWEBFORM模式中的HTTPHANDLER完毕了事件处理和页面显示的双重功能。而ASP.NETMVC没有事件处理,因此页面显示被划到了viewengine其中实现了。事件处理。被controller替换处理了。
微软的Razorview和Webformview本质上是实现于IView接口,而WebformViewengine和Webformview本质上是实现于IViewEngine
以下介绍他们的实现逻辑:
(參考引用:http://www.cnblogs.com/artech/archive/2012/08/22/view-engine-01.html)
自己定义的View以及相关的Viewengine,參考例如以下:
我们为Action方法ShowStaticFileView创建一个StaticFileView类型的View文件ShowStaticFileView.shtml(该View文件保存在“~/Views/Home”文件夹下,扩展名不是.cshtml,而是shtml),其内容就是例如以下一段完整的HTML。
(參考引用:/article/1308156.html)
,開始。
1、MVC的基本开发流程
2、webform和MVC的选择
3、MVC的内部过程
1、MVC的开发流程
MVC的出现时微软在2009年左右開始提出的站点开发的新的发展方向。这个方面的开发官方解释是能够比較好的实现三层分离,并且分离之后。能够实现复用等相关优点,通常人们列举的样例是ui方面能够同一时候支持HTML网络或者WAP网络。可是事实上个人的理解是,动态站点的开发经过不断地证实和发展,java的struts模型。能够提高开发速度。也能够减少差多。是比較好的框架。而微软也须要提供自己的开发框架。不能够仅仅是一个界面一个界面的设计方式,设计模式逐步进入到了web开发的领域。MVC使用vs2010进行开发时(这里介绍的是MVC2),首先须要选在一个模板,然后vs2010会帮忙创建好相应的文件夹结构。
每一个文件夹的基本功能:
Content:主要用于描写叙述css之类的资源
Controllers:主要就是controller的存放位置。创建controller时。都是须要在该文件夹创建的。
Models:主要就是entity的详细位置。以及跟entity相关的操作类
Scripts:javascript脚本存放的位置
Views:该部分主要是放置view显示部分的
Global.asax:眼下来看,该部分主要就是路由设置
Web.config:该配置文件而已
从开发的流程方面来看,MVC的开发方式,或者说思考的方式出现了变化,在MVC其中。须要理解一个重要的点是:
Controller才是系统的中心,一切环绕Controller展开。
Model:所谓模型,能够理解为数据,这个数据能够是数据库中相应的表中的数据,这样的数据是仅仅有属性,而没有动作的。这样的数据通常也被称之为Entity,即实体,除了这样的数据之外。MODLE起始还要包含Interface,这些接口的目标是提供能够控制Entity的接口标准,然后在提供实现的载体,通常我们称之为Mock类,为了方便,可能我们还会在Model其中创建各种factory。从而简化对象的创建。
Controller:这个部分就是核心了,事实上所谓核心,是说所有的处理,所有环绕着Controller展开,它的主要工作是訪问model,获取数据后,将參数转发给view,然后让view表现出来。
在这里主要完毕的工作有两点:
1、在client訪问一个页面后。须要跳转到Controller相应的action中去。然后在action中处理相应的view显示出来。
2、完毕客户的表单提交对应处理,也就是Form表单处理。(还记得之前讲过,对于HTML而言。仅仅有Form表单实现了client的信息发送给服务端。然后由服务端处理相关的对应,由于MVC的设计目标就是放弃了微软原有的server控件,因此一切回归原始,採用HTML的form表单方式实现提交和相关的控制处理。)
View:顾名思义,该部分就是现实的部分,这个部分须要时刻记住的是,这个view尽管也是aspx的页面,可是已经发生了根本性的变化,不再有所谓的codebeind代码了。这个view的全部变成将採用混合式的变成。你会注意到这个部分的变成变为HTML与C#的混合。会出现非常多的<%%><%=%>类似的代码。
非常多人起始对这个部分有不同的开发。混合代码对于分层不利。可是在MVC中,由于不涉及逻辑,所以view的表现变得简单。混合编程会变为能够接受的处理方式。
另外,这样的方式带来的优点是,美工能够介入了。他们的改动对于程序猿来说。没有什么特别,也是非常easy直接引入的。
带来的坏处是Gridview这样的强大的server控件被丢弃了。
尽管是这样。可是我个人认为。这是回到了web开发的本质。
他的思想,与JSP,PHP等等变为一致。
Golabal.asax:路由表。这个部分就是所谓的全局路由表。在MVC框架中。之所以实现了MVC功能,一个重要的概念是路由表,该部分实现了地址訪问的动态。不再提供详细页面的訪问模式。
注意:给我的感觉是,记住在view文件夹和model文件夹中。加入子文件夹,每一个controller相应的view,都是一个文件夹下的view。
这个是MVC框架查找时自己主动搜索的。
2、webform和MVC的选择
这个部分的争论,我想从微软開始推出MVC框架后。大家就在不间断的讨论着,不同的人,给出的看法也是不同。就我个人而言。我认为MVC才是未来趋势。是世界最后大同的根本。虽然webform的模式。是微软开创性的创造。可是毕竟web开发不是微软首创,非常多时候,大势所趋而已。我这里仅仅是想谈谈两者的思想出发点的区别:
webform模式。这个模式的思维基础,是微软在桌面开发中取得了前所未有的成功。这些成功,微软希望拷贝到网络开发中,何为form。就是窗体开发。这样的框架的逻辑是所见即所得+事件处理,微软希望可以将web实现为桌面开发的模式。可是网络开发的基础是HTML和HTTP协议,这两个部分带来的问题是HTML表现元素有限,而且仅仅可以通过form与后台server通信。另外,HTTP协议无状态,无法实现消息机制,为了解决这些问题,微软创造了新的开发模式,引入ASP.NETserver控件,实现了丰富的控件。通过postback回传机制,实现了事件模型,通过codebehind技术实现web页面与C#代码的分离。上述技术。的确非常成功,也确实非常大程度上简化了web的开发。可是随着发展,带来了问题,就是webform的开发基础是页面化的。这样的思维模式是说你开一个页面,然后在这个页面写响应事件。可是这样的模式对于频繁变化的web程序缺乏良好的复用性。而且,前端人员开发的界面。往往在合成时,须要重做,这是微软自己创造的困难。这是一种以Page为中心的开发思想。
MVC模式,这个模式的思维基础。是分工清晰,以Controller为核心。在开发时能够先做model再做Controller。最后做view,通过使用demoview实现。最后再替换美工的view。这样的模式变成了以数据为中心的开发思想。最大的优点是,这样的模式中每一个部分都能够灵活复用,最大限度的实现如今的各种网络须要。比方互联网和移动互联网。并且。其它的变成语言。在思想方面也基本採用这样的模式。这样的模式终于被时间证明。成为了标准思考方式和开发方式。微软提倡的桌面化开发,渐渐退却往日之光芒。
3、MVC的内部过程
这个部分是个很核心的问题,本文除了自己理解,还大量引用了其它相关的文章。尝试解说清楚MVC的基本运转流程。
MVC的主体过程:
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZG9uZ2Rvbmdkb25nSkw=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast"border="0">
问题:
1、浏览器请求的地址,并非详细的某个页面,如1234.aspx页面。而是controller/action方法。这是怎样做到的?
2、Controller被訪问到以后。怎样找到详细的view进行返回的?
我个人的理解就是回答了上述的问题,也就解释清楚了MVC的基本框架。
第一个问题,浏览器请求地址的问题。MVC之所以可以找到详细的Controller是由于有一个route组件。实现了路由处理的功能。将请求转化为Controller的详细方法。须要注意该组件竟然是个独立组件。
Routing的作用:
1、解析URL,识别其中的參数
2、解析之后。调用详细的controller和action
比方首页地址是:localhost/home/index
我们发现訪问上面的地址,
最后会传递给HomeController中名为index的action(即HomeController类中的index方法).
当然server端不会自己去实现这个功能,
关键点就是在Global.asax.cs文件里的下列代码:
publicstaticvoidRegisterRoutes(RouteCollectionroutes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default",//Routename
"{controller}/{action}/{id}",//URLwithparameters
new{controller="Home",action="Index",id=""}//Parameterdefaults
);
}
protectedvoidApplication_Start()
{
RegisterRoutes(RouteTable.Routes);
}
回来看我们的Url:localhost/home/index
localhost是域名,
所以首先要去掉域名部分:home/index
相应了上面代码中的这样的URL结构:{controller}/{action}/{id}
由于我们建立了这样的Url结构的识别规则,
所以可以识别出Controller是home,action是index,id没有则为默认值"".
上述功能之所以可以实现,关键在MapRoute方法。尽管MapRoute方法是RouteCollection对象的方法,可是却被放置在System.Web.Mvc程序集中,
假设你的程序仅仅引用了System.Web.Routing,
那么RouteCollection对象是不会有MapRoute方法的.
可是假设你同又引用了System.Web.Mvc,
则在mvc的dll中为RouteCollection对象加入了扩展方法:
publicstaticvoidIgnoreRoute(thisRouteCollectionroutes,stringurl);
publicstaticvoidIgnoreRoute(thisRouteCollectionroutes,stringurl,objectconstraints);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,string[]namespaces);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,objectconstraints);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,string[]namespaces);
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,objectconstraints,string[]namespaces);
RouteCollection是一个集合,他的每一项应该是一个Route对象.
可是我们使用MapRoute时并没有创建这个对象,
这是由于当我们将MapRoute方法须要的參数传入时,
在方法内部会依据參数创建一个Route对象:
publicstaticRouteMapRoute(thisRouteCollectionroutes,stringname,stringurl,objectdefaults,objectconstraints,string[]namespaces){
if(routes==null){
thrownewArgumentNullException("routes");
}
if(url==null){
thrownewArgumentNullException("url");
}
Routeroute=newRoute(url,newMvcRouteHandler()){
Defaults=newRouteValueDictionary(defaults),
Constraints=newRouteValueDictionary(constraints)
};
if((namespaces!=null)&&(namespaces.Length>0)){
route.DataTokens=newRouteValueDictionary();
route.DataTokens["Namespaces"]=namespaces;
}
routes.Add(name,route);
returnroute;
}
上面就是MapRoute方法的实现,
至于在创建Route对象时第二个參数是一个MvcRouteHandler,
它是一个实现了IRouteHandler接口的类.IRouteHandler十分简单仅仅有一个方法:
IHttpHandlerGetHttpHandler(RequestContextrequestContext);
參数是一个RequestContext
类实例,
这个类的结构也非常easy:
publicclassRequestContext
{
publicRequestContext(HttpContextBasehttpContext,RouteDatarouteData);
publicHttpContextBaseHttpContext{get;}
publicRouteDataRouteData{get;}
}
当中的一个属性RouteData就包括了Routing依据Url识别出来各种參数的值,
当中就有Controller和Action的值.
归根结底,ASP.NETMVC最后还是使用HttpHandler处理请求.ASP.NETMVC定义了自己的实现了IHttpHandler接口的Handler:MvcHandler,
由于MvcRouteHandler的GetHttpHandler方法最后返回的就是MvcHandler.
MvcHandler的构造函数须要传入RequestContext
对象,
也就是传入了全部的全部须要的数据,
所以最后能够找到相应的Controller和Action,
已经各种參数.
(引用參考:
(引用參考:/article/4677250.html)
第二个问题:Controller找到了,Action也找到了。此时怎样哪?
以下分层次的总结Controller处理流程:
1.页面处理流程
发送请求–>UrlRoutingModule捕获请求–>MvcRouteHandler.GetHttpHandler()–>MvcHandler.ProcessRequest()
2.MvcHandler.ProcessRequest()处理流程:
使用工厂方法获取详细的Controller–>Controller.Execute()–>
释放Controller对象
3.Controller.Execute()处理流程
获取Action–>
调用Action方法获取返回的ActionResult–>
调用ActionResult.ExecuteResult()方法
4.ActionResult.ExecuteResult()处理流程
获取IView对象->
依据IView对象中的页面路径获取Page类->
调用IView.RenderView()方法(内部调用Page.RenderView方法)
通过对MVC源码的分析,我们了解到Controller对象的职责是传递数据,获取View对象(实现了IView接口的类),通知View对象显示.View对象的作用是显示.尽管显示的方法RenderView()是由Controller调用的,可是Controller不过一个"指挥官"的作用,
详细的显示逻辑仍然在View对象中.须要注意IView接口与详细的ViewPage之间的联系.在Controller和View之间还存在着IView对象.对于ASP.NET程序提供了WebFormView对象实现了IView接口.WebFormView负责依据虚拟文件夹获取详细的Page类,然后调用Page.RenderView().
引用參考:(
说到这里。相信非常多人開始似乎明确了,又似乎不明确了,以下我做进一步的解说,先看一下。通常Controller的实现例如以下:
publicclassHomeController:Controller
{
publicActionResultIndex()
{
ReturnView(“Index”);
}
}
先看看关键类ActionResult。这个返回值。体现了微软精心设计。为什么做这么个类,事实上本质而言,微软希望这个action能够返回很多其它内容,而不不过view。
类名 | 抽象类 | 父类 | 功能 |
ContentResult | 依据内容的类型和编码,数据内容. | ||
EmptyResult | 空方法. | ||
FileResult | abstract | 写入文件内容,详细的写入方式在派生类中. | |
FileContentResult | FileResult | 通过文件byte[] 写入文件. | |
FilePathResult | FileResult | 通过文件路径写入文件. | |
FileStreamResult | FileResult | 通过文件Stream 写入文件. | |
HttpUnauthorizedResult | 抛出401错误 | ||
JavaScriptResult | 返回javascript文件 | ||
JsonResult | 返回Json格式的数据 | ||
RedirectResult | 使用Response.Redirect重定向页面 | ||
RedirectToRouteResult | 依据Route规则重定向页面 | ||
ViewResultBase | abstract | 调用IView.Render() | |
PartialViewResult | ViewResultBase | 调用父类ViewResultBase 的ExecuteResult方法. 重写了父类的FindView方法. 寻找用户控件.ascx文件 | |
ViewResult | ViewResultBase | 调用父类ViewResultBase 的ExecuteResult方法. 重写了父类的FindView方法. 寻找页面.aspx文件 |
在ASP.NETMVC中,ViewResult用的最多。Controller有一个View方法,它来实例化一个ViewResult对象,并返回。
以下是View方法:
protectedinternalvirtualViewResultView(stringviewName,stringmasterName,objectmodel){
if(model!=null){
ViewData.Model=model;
}
returnnewViewResult{
ViewName=viewName,
MasterName=masterName,
ViewData=ViewData,
TempData=TempData
};
}
ViewResult类的ExecuteResult方法的详细參考例如以下:
publicoverridevoidExecuteResult(ControllerContextcontext){
if(context==null){
thrownewArgumentNullException("context");
}
if(String.IsNullOrEmpty(ViewName)){
ViewName=context.RouteData.GetRequiredString("action");
}
ViewEngineResultresult=null;
if(View==null){
result=FindView(context);//非常关键。找到详细的view
View=result.View;
}
ViewContextviewContext=newViewContext(context,View,ViewData,TempData);
//非常关键,渲染自己
View.Render(viewContext,context.HttpContext.Response.Output);
if(result!=null){
result.ViewEngine.ReleaseView(context,View);
}
}
那么怎样FindView哪?详细例如以下:
rotectedoverrideViewEngineResultFindView(ControllerContextcontext){
ViewEngineResultresult=ViewEngineCollection.FindView(context,ViewName,MasterName);
if(result.View!=
null){
returnresult;
}
//weneedtogenerateanexceptioncontainingallthelocationswesearched
StringBuilderlocationsText=
newStringBuilder();
foreach(stringlocation
inresult.SearchedLocations){
locationsText.AppendLine();
locationsText.Append(location);
}
throw
newInvalidOperationException(String.Format(CultureInfo.CurrentUICulture,
MvcResources.Common_ViewNotFound,ViewName,locationsText));
}
从ViewResult类的FindView方法中,得知ViewEngineResult是通过ViewEngineCollection的FindView得到的。而ViewEngineCollection正是ViewEngines的静态属性Engines,Engines返回一个仅仅有一个WebFormViewEngine类型实例的一个集合。所以。ViewEngineResult会是调用WebFormViewEngine类的FindView方法返回的结果。
假设ViewEngins的静态属性Engines有多个ViewEngine提供。那么就依次遍历它们直到找到第一个不为空的ViewEngineResult为止。这样我们就能够在同一个MVC站点中使用多种视图引擎了。
静态类ViewEngines的描写叙述例如以下:
publicstaticclassViewEngines
{
privatestaticreadonlyViewEngineCollection_engines=newViewEngineCollection{newWebFormViewEngine(),newRazorViewEngine()};
publicstaticViewEngineCollectionEngines
{
get{return_engines;}
}
}
publicclassViewEngineCollection:Collection<IViewEngine>
{
//其它成员
publicvirtualViewEngineResultFindPartialView(ControllerContextcontrollerContext,stringpartialViewName);
publicvirtualViewEngineResultFindView(ControllerContextcontrollerContext,stringviewName,stringmasterName);
}
从上述样例能够看出,起始微软为我们提供了两个ViewEngine,WebFormViewEngine和RazorViewEngine,WebFormViewEngine相应的是ASPX界面,RazorViewEngine相应的是.cshtml/.vbhtml引擎
此外,这里有一个隐藏非常深的概念,似乎非常多书都没讲清楚。每个引擎都会相应一个view。作为页面渲染使用。对于viewengine做进一步的解释,就是说,为什么一个view其中的<%%>之类的界面元素最后能够变成html。就是这些引擎在起作用。他们的内部实现,能够提供类似正則表達式或者是页面parsing的方法,完毕页面字符串解析。从而转换为相应的html,再response给client浏览器。
微软提供的两种viewengine和view例如以下:
RazorViewEngine和Razorview
(參考引用:http://www.cnblogs.com/artech/archive/2012/09/05/razor-view-engine-02.html)
WebformViewengine和Webformview
通过上边的讲述。主要的概念已经讲清楚了,假设希望实现自己的viewengine,能够查看一下微软參考实现是怎样做到的,然后我们就能够防治自己的viewengine了。这里便须要进一步说明的是。为什么MVC须要viewengine。而WEBFORM不须要,是由于,微软的webform是直接通过IHttphandler处理了,也就是说ASP.NETWEBFORM模式中的HTTPHANDLER完毕了事件处理和页面显示的双重功能。而ASP.NETMVC没有事件处理,因此页面显示被划到了viewengine其中实现了。事件处理。被controller替换处理了。
微软的Razorview和Webformview本质上是实现于IView接口,而WebformViewengine和Webformview本质上是实现于IViewEngine
以下介绍他们的实现逻辑:
publicinterfaceIView
2:{
3:voidRender(ViewContextviewContext,TextWriterwriter);
4:}
5:
6:publicclassViewContext:ControllerContext
7:{
8://其它成员
9:publicvirtualboolClientValidationEnabled{get;set;}
10:publicvirtualboolUnobtrusiveJavaScriptEnabled{get;set;}
11:
12:publicvirtualTempDataDictionaryTempData{get;set;}
13:[Dynamic]
14:publicobjectViewBag{[return:Dynamic]get;}
15:publicvirtualViewDataDictionaryViewData{get;set;}
16:publicvirtualIViewView{get;set;}
17:publicvirtualTextWriterWriter{get;set;}
18:}
19:
20:publicabstractclassHttpResponseBase
21:{
22://其它成员
23:publicvirtualTextWriterOutput{get;set;}
24:}
1:publicinterfaceIViewEngine
2:{
3:ViewEngineResultFindPartialView(ControllerContextcontrollerContext,stringpartialViewName,booluseCache);
4:ViewEngineResultFindView(ControllerContextcontrollerContext,stringviewName,stringmasterName,booluseCache);
5:voidReleaseView(ControllerContextcontrollerContext,IViewview);
6:}
1:publicclassViewEngineResult
2:{
3:publicViewEngineResult(IEnumerable<string>searchedLocations);
4:publicViewEngineResult(IViewview,IViewEngineviewEngine);
5:
6:publicIEnumerable<string>SearchedLocations{get;}
7:publicIViewView{get;}
8:publicIViewEngineViewEngine{get;}
9:}
1:publicclassViewResult:ViewResultBase
2:{
3:protectedoverrideViewEngineResultFindView(ControllerContextcontext);
4:publicstringMasterName{get;set;}
5:}
6:
7:publicabstractclassViewResultBase:ActionResult
8:{
9:publicoverridevoidExecuteResult(ControllerContextcontext);
10:protectedabstractViewEngineResultFindView(ControllerContextcontext);
11:
12:publicobjectModel{get;}
13:publicTempDataDictionaryTempData{get;set;}
14:[Dynamic]
15:publicobjectViewBag{[return:Dynamic]get;}
16:publicViewDataDictionaryViewData{get;set;}
17:publicstringViewName{get;set;}
18:publicViewEngineCollectionViewEngineCollection{get;set;}
19:publicIViewView{get;set;}
20:}
(參考引用:http://www.cnblogs.com/artech/archive/2012/08/22/view-engine-01.html)
自己定义的View以及相关的Viewengine,參考例如以下:
publicclassStaticFileView:IView
2:{
3:publicstringFileName{get;privateset;}
4:publicStaticFileView(stringfileName)
5:{
6:this.FileName=fileName;
7:}
8:publicvoidRender(ViewContextviewContext,TextWriterwriter)
9:{
10:byte[]buffer;
11:using(FileStreamfs=newFileStream(this.FileName,FileMode.Open))
12:{
13:buffer=newbyte[fs.Length];
14:fs.Read(buffer,0,buffer.Length);
15:}
16:writer.Write(Encoding.UTF8.GetString(buffer));
17:}
18:}
internalclassViewEngineResultCacheKey
2:{
3:publicstringControllerName{get;privateset;}
4:publicstringViewName{get;privateset;}
5:
6:publicViewEngineResultCacheKey(stringcontrollerName,stringviewName)
7:{
8:this.ControllerName=controllerName??
string.Empty;
9:this.ViewName=viewName??string.Empty;
10:}
11:publicoverrideintGetHashCode()
12:{
13:returnthis.ControllerName.ToLower().GetHashCode()^this.ViewName.ToLower().GetHashCode();
14:}
15:
16:publicoverrideboolEquals(objectobj)
17:{
18:ViewEngineResultCacheKeykey=objasViewEngineResultCacheKey;
19:if(null==key)
20:{
21:returnfalse;
22:}
23:returnkey.GetHashCode()==this.GetHashCode();
24:}
25:}
1:publicclassStaticFileViewEngine:IViewEngine
2:{
3:privateDictionary<ViewEngineResultCacheKey,ViewEngineResult>viewEngineResults=newDictionary<ViewEngineResultCacheKey,ViewEngineResult>();
4:privateobjectsyncHelper=newobject();
5:publicViewEngineResultFindPartialView(ControllerContextcontrollerContext,stringpartialViewName,booluseCache)
6:{
7:returnthis.FindView(controllerContext,partialViewName,null,useCache);
8:}
9:
10:publicViewEngineResultFindView(ControllerContextcontrollerContext,stringviewName,stringmasterName,booluseCache)
11:{
12:stringcontrollerName=controllerContext.RouteData.GetRequiredString("controller");
13:ViewEngineResultCacheKeykey=newViewEngineResultCacheKey(controllerName,viewName);
14:ViewEngineResultresult;
15:if(!useCache)
16:{
17:result=InternalFindView(controllerContext,viewName,controllerName);
18:viewEngineResults[key]=result;
19:returnresult;
20:}
21:if(viewEngineResults.TryGetValue(key,outresult))
22:{
23:returnresult;
24:}
25:lock(syncHelper)
26:{
27:if(viewEngineResults.TryGetValue(key,outresult))
28:{
29:returnresult;
30:}
31:
32:result=InternalFindView(controllerContext,viewName,controllerName);
33:viewEngineResults[key]=result;
34:returnresult;
35:}
36:}
37:
38:privateViewEngineResultInternalFindView(ControllerContextcontrollerContext,stringviewName,stringcontrollerName)
39:{
40:string[]searchLocations=newstring[]
41:{
42:string.Format("~/views/{0}/{1}.shtml",controllerName,viewName),
43:string.Format("~/views/Shared/{0}.shtml",viewName)
44:};
45:
46:stringfileName=controllerContext.HttpContext.Request.MapPath(searchLocations[0]);
47:if(File.Exists(fileName))
48:{
49:returnnewViewEngineResult(newStaticFileView(fileName),this);
50:}
51:fileName=string.Format(@"\views\Shared\{0}.shtml",viewName);
52:if(File.Exists(fileName))
53:{
54:returnnewViewEngineResult(newStaticFileView(fileName),this);
55:}
56:returnnewViewEngineResult(searchLocations);
57:}
58:
59:publicvoidReleaseView(ControllerContextcontrollerContext,IViewview)
60:{}
61:}
1:publicclassMvcApplication:System.Web.HttpApplication
2:{
3:protectedvoidApplication_Start()
4:{
5://其它操作
6:ViewEngines.Engines.Insert(0,newStaticFileViewEngine());
7:}
8:}
1:publicclassHomeController:Controller
2:{
3:publicActionResultShowNonExistentView()
4:{
5:returnView("NonExistentView");
6:}
7:
8:publicActionResultShowStaticFileView()
9:{
10:returnView();
11:}
12:}
我们为Action方法ShowStaticFileView创建一个StaticFileView类型的View文件ShowStaticFileView.shtml(该View文件保存在“~/Views/Home”文件夹下,扩展名不是.cshtml,而是shtml),其内容就是例如以下一段完整的HTML。
1:<!DOCTYPEhtml>
2:<html>
3:<head>
4:<title>StaticFileView</title>
5:</head>
6:<body>
7:这是一个自己定义的StaticFileView。
8:</body>
9:</html>
(參考引用:
相关文章推荐
- ASP.NET内置对象二
- RaspberryPi 和摄像头的结合
- How to customize authentication to my own set of tables in asp.net web api 2?
- C#分页代码,或许这个代码比Asp.Net分页和AspNetPager控件更好用
- 理解SVG的viewport,viewBox,preserveAspectRatio
- 解析ASP.NET Mvc开发之EF延迟加载
- 再谈ASP.NET第七 - 跨应用、跨服务器的表单验证
- ASP.NET动态网站制作(5)-- 标签语义化及知识补充
- ASP.NET动态网站制作(4)--css(3)
- asp.net web forms page life cycle
- ASP.NET - cookie
- asp.net iis7 提示:在多字节的目标代码页中,没有此 Unicode 字符可以映射到的字符 错误的解决方案
- ASP.NET 5 和Entity Framework 7公告仓库
- AspectJ的简单使用
- ASP 页的执行造成响应缓冲区超过其配置限制
- asp.net TreeView 的使用
- asp.net TreeView 的使用
- ASP.NET\ASP.NET MVC表单提交遇到的问题结论
- ASP.NET内置对象一
- ASP.NET Web API实现微信公众平台开发(三)自定义菜单