关闭

关闭

关闭

封号提示

内容

首页 mvc3.pdf

mvc3.pdf

mvc3.pdf

上传者: envoyaaa 2012-07-05 评分 0 0 0 0 0 0 暂无简介 简介 举报

简介:本文档为《mvc3pdf》,可适用于IT/计算机领域,主题内容包含AspNetMVC简单入门第一季(三)详解Controller之Filter::我来说两句收藏我要投稿字体:小大前言前面两篇写的比较简单刚开始写这个符等。

AspNetMVC简单入门第一季(三)详解Controller之Filter::我来说两句收藏我要投稿字体:小大前言前面两篇写的比较简单刚开始写这个系列的时候我面向的对象是刚开始接触AspNetMVC的朋友所以写的尽量简单。所以写的没多少技术含量。把这些技术总结出来然后一简单的方式让更多的人很好的接受这是我一直努力的方向。后面会有稍微复杂点的项目!让我们一起期待吧!此文我将跟大家介绍一下AspNetMVCFilter的一些用法。你会了解和学习到全局FileterActionFilter等常用用法。第一节:Filter知识储备项目大一点总会有相关的AOP面向切面的组件而MVC(特指:AspNetMVC以下皆同)项目中呢Action在执行前或者执行后我们想做一些特殊的操作(比如身份验证日志异常行为截取等)而不想让MVC开发人员去关心和写这部分重复的代码那我们可以通过AOP截取实现而在MVC项目中我们就可以直接使用它提供的Filter的特性帮我们解决不用自己实现复杂的AOP了。AspNetMVC提供了以下几种默认的Filter:FilterType实现接口执行时间DefaultImplementationAuthorizationfilterIAuthorizationFilter在所有Filter和Action执行之前执行AuthorizeAttributeActionfilterIActionFilter分别在Action执行之前和之后执行。ActionFilterAttributeResultfilterIResultFilter分别在ActionResult执行之后和之前ResultFilterAttributeExceptionfilterIExceptionFilter只有在filter,或者actionmethod,或者actionresult抛出一个异常时候执行HandleErrorAttribute大家注意一点AspNetMVC提供的ActionFilterAttribute默认实现了IActionFilter和IResultFilter。而ActionFilterAttribute是一个Abstract的类型所以不能直接使用因为它不能实例化所以我们想使用它必须继承一下它然后才能使用下图所示的是ActionFilterAttribute的实现:所以我们在实现了ActionFilterAttribute然后就可以直接重写一下父类的方法如下:publicvirtualvoidOnActionExecuted(ActionExecutedContextfilterContext)在Action执行之后执行publicvirtualvoidOnActionExecuting(ActionExecutingContextfilterContext)在Action执行前执行publicvirtualvoidOnResultExecuted(ResultExecutedContextfilterContext)在Result执行之后publicvirtualvoidOnResultExecuting(ResultExecutingContextfilterContext)在Result执行之前然后我们就可以直接在Action、Result执行之前之后分别做一些操作。第二节:ActionFilter实战光说不练假把式那现在我们就直接做一个例子来实际演示一下。首先我们添加一个普通的类直接上代码吧:publicclassDemoActionAttributeFilter:ActionFilterAttribute{publicstringMessage{getset}publicoverridevoidOnActionExecuted(ActionExecutedContextfilterContext){在Action执行之后执行输出到输出流中文字:AfterActionExcutexxxfilterContextHttpContextResponseWrite("<br>AfterActionExcute""t"Message)baseOnActionExecuted(filterContext)}publicoverridevoidOnActionExecuting(ActionExecutingContextfilterContext){在Action执行前执行filterContextHttpContextResponseWrite("<br>BeforeActionExcute""t"Message)baseOnActionExecuting(filterContext)}publicoverridevoidOnResultExecuted(ResultExecutedContextfilterContext){在Result执行之后filterContextHttpContextResponseWrite("<br>AfterViewResultExcute""t"Message)baseOnResultExecuted(filterContext)}publicoverridevoidOnResultExecuting(ResultExecutingContextfilterContext){在Result执行之前filterContextHttpContextResponseWrite("<br>BeforeViewResultExcute""t"Message)baseOnResultExecuting(filterContext)}}写完这个代码后我们回到Action上打上上面的标记如下所示:DemoActionAttributeFilter(Message="action")publicActionResultIndex(){Action执行时往输出流写点代码thisControllerContextHttpContextResponseWrite("<br>ActionExcute")returnContent("ResultExcut!")}然后执行F页面上则会显示为:最终我们看到了在Action执行之前和之后都执行了我们的重写的DemoActionAttributeFilter方法Result执行前后也执行了我们的Filter的方法。总的执行顺序是:Action执行前:OnActionExecuting方法先执行Action执行OnActionExecuted方法执行OnResultExecuting方法执行返回的ActionRsult中的ExcuteResult方法执行OnResultExecuted执行。最终显示的效果就是如上图所示。感觉很爽吧!呵呵!如果我们将此标签打到Controller上的话DemoActionAttributeFilter将作用到Controller下的所有的Action。例如如下代码所示:DemoActionAttributeFilter(Message="controller")publicclassHomeController:Controller{DemoActionAttributeFilter(Message="action")publicActionResultIndex(){thisControllerContextHttpContextResponseWrite("<br>ActionExcute")returnContent("<br>ResultExcut!")}}那就有个问题了我们再执行显示的页面会有什么情况呢?Controller上的Filter会执行吗?那标签的作用会执行两次吗?下面是最后的执行结果如下图所示:结果说明:默认情况下Action上打了DemoActionAttributeFilter标签后虽然在Controller上也打上了此标签但它只有Action上的标签起作用了。Index执行时Filter的方法只执行了一次而某些情况下我们也想让Controller上的FilterAttribute也执行一次DemoActionAttributeFilter那我们怎么才能让Controller上的DemoActionAttributeFilter(Message="controller")也起作用呢?答案是:我们只需在DemoActionAttributeFilter类的定义上打上标记AttributeUsage(AttributeTargetsAll,AllowMultiple=true)即可【下面类的最上面红色字体部分】也就是让其成为可以多次执行的Action。代码如下:AttributeUsage(AttributeTargetsAll,AllowMultiple=true)publicclassDemoActionAttributeFilter:ActionFilterAttribute{publicstringMessage{getset}publicoverridevoidOnActionExecuted(ActionExecutedContextfilterContext){filterContextHttpContextResponseWrite("<br>AfterActionExcute""t"Message)baseOnActionExecuted(filterContext)}publicoverridevoidOnActionExecuting(ActionExecutingContextfilterContext){filterContextHttpContextResponseWrite("<br>BeforeActionExcute""t"Message)baseOnActionExecuting(filterContext)}publicoverridevoidOnResultExecuted(ResultExecutedContextfilterContext){filterContextHttpContextResponseWrite("<br>AfterViewResultExcute""t"Message)baseOnResultExecuted(filterContext)}publicoverridevoidOnResultExecuting(ResultExecutingContextfilterContext){filterContextHttpContextResponseWrite("<br>BeforeViewResultExcute""t"Message)baseOnResultExecuting(filterContext)}}然后我们执行的效果如图所示:我们看到的结果是Controller上的ActionFilter先于Action上打的标记执行。同样Result执行ExcuteResult方法之前也是先执行Controller上的Filter标记中的OnResultExcuteing方法。最后的执行顺序是:Controller上的OnActionExecutingAction上的OnActionExecutingAction执行Action上的OnActionExecutedController上的OnActionExecuted到此Action就执行完毕了我们看到是一个入栈出栈的顺序。后面是Action返回ActionResult后执行了ExecuteResult方法但在执行之前要执行Filter。具体顺序为:接上面Controller的OnResultExecuting方法Action上的OnResultExecutingAction返回ActionResult后执行了ExecuteResult方法Action上的OnResultExecuted执行Controller上的OnResultExecuted执行结束第三节:GloableFilter实战又接着一个问题也来了我们想有些公共的方法需要每个Action都执行以下而在所有的Controller打标记是很痛苦的。幸好Asp。NetMVC带来了一个美好的东西全局Filter。而怎么注册全局Filter呢?答案就在Globalasax中。让我们看以下代码我是如何将上面我们定义的DemoActionAttributeFilter注册到全局Filter中。上代码:publicclassMvcApplication:SystemWebHttpApplication{publicstaticvoidRegisterGlobalFilters(GlobalFilterCollectionfilters){filtersAdd(newHandleErrorAttribute())}publicstaticvoidRegisterRoutes(RouteCollectionroutes){routesIgnoreRoute("{resource}axd{*pathInfo}")routesMapRoute("Default",Routename"{controller}{action}{id}",URLwithparametersnew{controller="Home",action="Index",id=UrlParameterOptional}Parameterdefaults)}protectedvoidApplicationStart(){AreaRegistrationRegisterAllAreas()GlobalFiltersFiltersAdd(newDemoActionAttributeFilter(){Message="Gloable"})RegisterGlobalFilters(GlobalFiltersFilters)RegisterRoutes(RouteTableRoutes)}}跟普通的MVC中的Globalasax的区别就是红色部分的代码我们看到代码中我将自己定义的DemoActionAttributeFilter的实例加入到GlobalFiltersFilters集合中然后下面一句就是注册全局Filter:RegisterGlobalFilters(GlobalFiltersFilters)这样我们所有的Action和Result执行前后都会调用我们的DemoActionAttributeFilter的重写的方法。再次运行我们的demo看到的结果是:我们看到的结果是全局的Action首先执行然后才是Controller下的Filter执行最后才是Action上的标签执行。当然这是在DemoActionAttributeFilter类的定义上打上标记AttributeUsage(AttributeTargetsAll,AllowMultiple=true)的前提下。不然如果Action打上了标签跟Controller的相同则它只会执行Action上的Filter。总结经过这一篇文章的介绍我们大体了解了Filter的使用方法还了解到全局Filter的用法尤其是当相同的Filter重复作用到同一个Action上时如果没有设置可多次执行的标签那只有Action上的Filter执行而Controller和全局Filter都被屏蔽掉但是设置可多次执行那首先执行全局Filter其次是Controller再次之就是Action上的Filter了。AspNetMVC简单入门第一季(四)详解RequestProcessingPipeline::我来说两句收藏我要投稿字体:小大引子很久没更新了今天写点关于AspNetMVC的PipeLine。首先我们确认一点AspNetWebFrom和AspNetMVC是在Net平台下的两种web开发方式。其实他们都是基于AspNetCore的不同表现而已。看下面一张图我们就能理解了WebForm和AspNetMVC的一个关系了。那好我们了解了AspNet平台下的两种开发方式相信大家对于WebForm的Pipeline都非常熟悉了当然这也是你熟悉AspNet开发的必经之路。而看了很多关于AspNetMVC的资料很少有把整个Pipeline讲的非常清楚的。我暂时将自己浅陋的整理和理解总结如下欢迎高手拍装!第一阶段:客户端请求客户端通过浏览器、其他软件、自己编写WebClinet、模拟HttpRequest等方法来请求一个URL。当然在AspNetWebFrom下所有的请求都是归结到Handler上普通的Aspx、Ascx等都是继承自IHttpHandler接口的一些实例所以我总结出来:WebFrom下所有的请求都是请求的Handler【不考虑Url重写】。而做AspNetMVC的项目呢所有的请求是都归结到Action上Url应该是直接请求Action。客户端发出请求后此请求就会通过网络发出可能经过多个路由、还可能经过域名解析等等最后可能请求的是一个集群IP但是最终肯定只能由一台Web服务器的来处理此次请求。第二阶段:IISWeb服务器当一个请求到达IIS服务器后Windows系统的内核模块HTTPSYS就能监听到此次请求并将此次请求的URL、IP以及端口等信息解析出来并将次请求交给注册的应用来处理:也就是IIS的站点。请求此时就到达了IISIIS【此处仅代表IIS版本】就会去检查此次请求的URL的后缀并将相应的请求交给配置的处理后缀相应的isapi。如果是aspx或者ascx等直接交给默认设置了此处理项的AspNetisapidll来处理如果我们想处理AspNetMVC的请求的话我们需要在IIS里面设置处理**请求交给AspNetisapidll来处理才能将一个普通的MVC请求的URL:Http:localhostDemoControllerDemoAction交给AspNetIsapidll来处理。第三阶段:AspNet运行时此时请求到AspNetIsapidll后它负责启动AspNetRunTime【如过启动了直接将请求交给RunTime】。AspNet运行时此时会初始化一下HttpContext上下午并从应用池中去取一个HttpApplication对象并将HttpContext赋值给HttpApplication此后HttpContext的信息就会一直在管道内往下传递。HttpApplication对象开始初始化WebConfig文件中注册的IHttpModule请求带着请求信息【HttpContext】随着管道流过多个HttpModule【一般可以做为权限校验、行为记录、日志等等就是在到达Handler之前我们都可以直接处理此次Http请求甚至可以重写URL】当然也会经过我们注册的一些自定义的IHttpModule在Net的machine的config文件中默认配置了一个URLRouteModule这个也就是我们普通的AspNetMVC项目中的路由DLL引用【SystemWebRouting】内部的一个实现了IHttpModule接口的实现。请求最终流向了路由组件。第四阶段:Routing组件如果你用的是MVCNET则你会在你的web项目中发现UrlRoutingModule就配置在你的WebConfig。NET却是在Net的默认配置文件中配置的。UrlRoutingModule做了这么几个工作:首先他会拿着你的请求到路由表中去匹配相应的路由规则。而路由表规则的定义是在HttpApplication初始化的时候由静态方法执行的且看一个普通的AspNetMVC项目的GlobalasaxpublicclassMvcApplication:SystemWebHttpApplication{publicstaticvoidRegisterGlobalFilters(GlobalFilterCollectionfilters){filtersAdd(newHandleErrorAttribute())}publicstaticvoidRegisterRoutes(RouteCollectionroutes)定义路由表规则{routesIgnoreRoute("{resource}axd{*pathInfo}")routesMapRoute("Default",路由名称"{controller}{action}{id}",带有参数的URLnew{controller="Home",action="Index",id=UrlParameterOptional}参数默认值)}protectedvoidApplicationStart(){AreaRegistrationRegisterAllAreas()RegisterGlobalFilters(GlobalFiltersFilters)RegisterRoutes(RouteTableRoutes)注册路由表}}而路由表的规则的注册是在ApplicationStart()方法内部那此时请求在URLRouteModule内部到路由表中的所有规则进行匹配并把匹配的Controller的信息和Action的信息以及RouteData等信息都解析处理然后将请求进一步交给:实现了IRouteHandler【实现了IHttpHandler接口】的一个实例下面是IRouteHandler的源码:namespaceSystemWebRouting{publicinterfaceIRouteHandler{IHttpHandlerGetHttpHandler(RequestContextrequestContext)}}如果你想自己来实现这个接口然后在WebConfig中配置一下那么请求就到了你自己的自定义的RouteHandler来执行后续的请求处理操作了。如果你使用的是默认的配置那么请求会传递到MvcRouteHandler那么请求f附加着HttpContext就会到达AspNetMVC的处理中了。第五阶段:MvcRouteHandler创建Controller并调用其Excute方法请求到此其实跟WebForm都是一致的而后面才出现了一些不同此时请求才真正的进入SystemWebMvc控制的领域内。后面所有的东西我们都可以直接通过源码来介绍了而上面的所有的请求处理只能通过反射等方式来看或者学习而后面的内容我们可以幸福的直接看源码了。那就跟我走进它的管道怎么流动的吧接着上面讲请求到了MvcRouteHandler类而此类的源码如下:namespaceSystemWebMvc{usingSystemWebRoutingusingSystemWebSessionStatepublicclassMvcRouteHandler:IRouteHandler{privateIControllerFactorycontrollerFactorypublicMvcRouteHandler(){}publicMvcRouteHandler(IControllerFactorycontrollerFactory){controllerFactory=controllerFactory}protectedvirtualIHttpHandlerGetHttpHandler(RequestContextrequestContext)实现了IRouteHandler的方法URLRouteModule调用{requestContextHttpContextSetSessionStateBehavior(GetSessionStateBehavior(requestContext))returnnewMvcHandler(requestContext)}}MvcRouteHandler的GetHttpHandler方法被URLRouteModule调用而看上面的红色源码部分我们看到它将请求上下文交给了MVCHandler并返回了MVCHandler。而我查看源码得知:MVCHandler实现了IHttpHandler此时它的ProcessRequest方法被调用。且看MVCHandler的部分源代码:publicclassMvcHandler:IHttpAsyncHandler,IHttpHandler,IRequiresSessionState{protectedinternalvirtualvoidProcessRequest(HttpContextBasehttpContext){SecurityUtilProcessInApplicationTrust(()=>{IControllercontroller在ProcessRequestInit方法中:controller=factoryCreateController(RequestContext,controllerName)初始化IControllerFactoryfactory是由ProcessRequestInit方法中这行代码初始化的:factory=ControllerBuilderGetControllerFactory()ProcessRequestInit(httpContext,outcontroller,outfactory)初始化了ControllerFactorytry{controllerExecute(RequestContext)}finally{factoryReleaseController(controller)}})}}从源码中我们得知:请求交给MVCHandler后它首先从ControllerBuilder获取到当前的实现了IControllerFactory接口的ControllerFactory【也可以自己定义相关的CustomerControllerFactory然后在Glable中注册使用】。然后根据上下文中请求的Controller的字符串信息创建出实现了IController接口的控制器。然后调用了上面代码中红色部分也就是controllerExecute(RequestContext)那此时请求就交给了controller。第六阶段:Controller调用Action返回ActionResult并调用ExcuteResult方法由于此文过长而且时间已经到了凌晨。源码我就不贴了简单介绍一下流程后面再做详细赘述。Controller的Execute方法是在基类ControllerBase中的方法而此方法又调用ExecuteCore方法然后此方法内部执行如下代码:stringactionName=RouteDataGetRequiredString("action")if(!ActionInvokerInvokeAction(ControllerContext,actionName)){HandleUnknownAction(actionName)}首先从RouteData中获取Action的名字然后调用ActonInvoker的InvokeAction方法调用Action执行。Action的返回的ActionResult的ExecuteResult(controllerContext)方法被执行那此时就出现了分叉。如果直接返回的非ViewResult的话那就直接协会到Respose流了返回客户端了如果是ViewResult的话那就进入View的领域了。第七阶段:View视图加载成Page类并Render成Html写回客户端此时请求到ViewResult后ExcuteResult方法被调用且看此方法的内部实现:publicoverridevoidExecuteResult(ControllerContextcontext){if(context==){thrownewArgumentException("context")}if(StringIsOrEmpty(ViewName)){ViewName=contextRouteDataGetRequiredString("action")}ViewEngineResultresult=if(View==){result=FindView(context)通过视图引擎获取到ViewEngineResult此时模板页面【aspx】被加载成了对应的ViewPage类View=resultView}TextWriterwriter=contextHttpContextResponseOutputViewContextviewContext=newViewContext(context,View,ViewData,TempData,writer)ViewRender(viewContext,writer)if(result!=){resultViewEngineReleaseView(context,View)}}内部主要是通过ViewResult的FindView方法通过ViewEngine去加载具体的Aspx页面或者是cshtml页面生成对应的page类【针对Aspx】然后再调用IView接口的Render方法将请求信息ViewData的信息以等一块渲染成Html并写回到客户端。在此阶段我们发现IViewEngine内部的实现这是到规定路径下去加载Aspx页面生成对应的ViewPage类。IView接口的Render方法才是真正的去讲Html和数据装配的到一块。自此请求结束。总结:客户端请求路由器IIS服务器内核模块HTTPSYSIISAspNetisapidllAspNetRuntimeApplicationIHttpModuleIHttpModuleMVCRouteModuleMVCRouteHandlerMVCHandlerControllerFactoryControllerActionInvokeAcitonActiongResultExcuteReuslt()【如果是ViewResult】IViewEngineFindViewIViewRenderResponse最后附两张关于此请求管道的两张图以飨读者。

热点搜索换一换

用户评论(0)

0/200

精彩专题

上传我的资料

每篇奖励 +2积分

资料评价:

/20
0下载券 下载 加入VIP, 送下载券

意见
反馈

立即扫码关注

爱问共享资料微信公众号

返回
顶部