Controller总结

下图显示了组建之间的基本控制流程

1.1控制器工厂、动作调用器

控制器工厂负责创建对请求进行服务的控制器实例

动作调用其负责查找并调用控制器类中的动作方法。

1.2自定义控制器工厂

namespace System.Web.Mvc{

    // 摘要:定义控制器工厂所需的方法。

    public interface IControllerFactory{

        // 摘要:使用指定的请求上下文来创建指定的控制器。

        // 参数:requestContext:

        //     请求上下文。

        //   controllerName:

        //     控制器的名称。

        // 返回结果:控制器。

        IController CreateController(RequestContext requestContext, string controllerName);

        // 摘要:获取控制器的会话行为。

        // 参数:

        //   requestContext:

        //     请求上下文。

        //   controllerName:

        //     你想要获取器其会话行为的控制器的名称。

        // 返回结果:

        //     控制器的会话行为。

        SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);

        // 摘要:

        //     释放指定的控制器。

        // 参数:

        //   controller:

        //     控制器。

        void ReleaseController(IController controller);

    }

}

public class CustomControllerFactory : IControllerFactory{

        /// <summary>

        /// 创建能够对当前请求进行处理的控制器实例

        /// </summary>

        public IController CreateController(RequestContext requestContext, string controllerName)

        {

            Type targetTtpe = null;

            switch (controllerName) {

                case "Product":

                    targetTtpe = typeof(ProductController);

                    break;

                case "Customer":

                    targetTtpe = typeof(CustomerController);

                    break;

                default:

//默认情况下mvc会根据路由数据中controller的值来选择视图,而不是控制器名称

                    requestContext.RouteData.Values["controller"] = "Product";

                    targetTtpe = typeof(ProductController);

                    break;

            }

            //通过依赖关系解析器(DependencyResolver)注册对象

            return targetTtpe == null ? null : (IController)DependencyResolver.Current.GetService(targetTtpe);

        }

        public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)

        {

//SessionStateBehavior枚举类型

            //Default  使用默认 ASP.NET 逻辑来确定请求的会话状态行为

            //Required 为请求启用完全的读写会话状态行为

            //ReadOnly 为请求启用只读会话状态。

            //Disabled 未启用会话状态来处理请求。

            return SessionStateBehavior.Default;

        }

        public void ReleaseController(IController controller)

        {

            IDisposable disposable = controller as IDisposable;

            if (disposable != null) {

                disposable.Dispose();

            }

        }

}

这个接口中最重要的是CreateController(),当MVC框架需要控制器对请求进行服务时,便会调用这个方法。该方法的一个参数是RequestContext对象,它让工厂能够检测请求的细节;另一个参数是字符串,它包含了从路由的URL哪里所得到的controller的值

RequestContext属性


名称


类型


描述


HttpContext


HttpContextBase


提供关于HTTP请求信息


RouteData


RouteData


提供与请求匹配的路由信息

不建议这样创建自定义控制器的原意之一是,在Web应用程序中查找控制器类并对他们实例化是复杂的,且有潜在风险的eg,消除不同命名空间中同名类之间的歧义、构造函数异常。

 

默认情况下MVC框架会根据路由数据中controller的值来选择视图,而不是控制器类的名称(如果请求时一个不正确的URL,则路由数据中controller的值所指的就可能是一个不存在的控制器)。

1.3使用内建的控制器工厂--DefaultControllerFactory

该类维护者应用程序中这些类的一个列表,因此,一个请求到达时,它并不需要每次都执行一个搜索(不需要每次都通过搜索来简历这个控制器类的列表)。如果找到一个合适的类,便用控制器激活器(ControllerActivator)创建一个实例。

注意:遵循约定由于配置模式

 

定制DefaultControllerFactory的控制器实例化

①使用依赖性注解器:通过第三方的Ninject,NinjectDependencyResolver类实现IDependencyResolver接口以提供Ninject的DI支持。

②使用控制器激活器:使用控制器激活器(Controller Activator)的办法将DI引入到控制器中。实现IControllerActivator接口创建激活器

namespace System.Web.Mvc{

    // 摘要:对使用依赖关系注入来实例化控制器的方式进行精细控制。

    public interface IControllerActivator{

        // 摘要:在类中实现时创建控制器。

        // 参数:

        //   requestContext:

        //     请求上下文。

        //   controllerType:

        //     控制器类型。

        // 返回结果:

        //     创建的控制器。

        IController Create(RequestContext requestContext, Type controllerType);

    }

}

实现IControllerActivator

public class CustomControllerActivator : IControllerActivator

    {

        public IController Create(RequestContext requestContext, Type controllerType)

        {

            if (controllerType == typeof(ProductController)) {

                controllerType = typeof(CustomerController);

            }

            return (IController)DependencyResolver.Current.GetService(controllerType);

        }

}

此伪代码很简单,如果请求的是ProductController将以CustomerController类的实例作为响应。仅用于演示了如何利用IControllerActivator接口在控制器工厂和依赖性解析器之间截取请求。

为了使用自定义激活器,需要为构造器传递一个实现类的实例并在application_start()中注册

protected void Application_Start(){

            AreaRegistration.RegisterAllAreas();

            RouteConfig.RegisterRoutes(RouteTable.Routes);

            ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new CustomControllerActivator()));

        }

③重写DefaultControllerFactory()

 

1.4创建自定义动作调用器

控制器控场创建了一个控制器类的实例,框架就需要一种办法来调用这个实例上的一个动作。如果控制器是通过Controller类派生而来的,那么将由动作调用其(Action Invoker)调用动作。

备注:如果直接通过IController创建控制器,则要自己去负责执行动作

namespace System.Web.Mvc{

    public interface IActionInvoker{

        // 摘要:

        //     使用指定的控制器上下文来调用指定动作。

        // 参数:

        //   controllerContext:

        //     控制器上下文。

        //   actionName:

        //     操作的名称。

        // 返回结果:

        //     如果找到了指定动作,则为 true;否则为 false。

        bool InvokeAction(ControllerContext controllerContext, string actionName);

     }

}

注意:注释中的动作对应上边的动作,动作与动作方法不同。

动作时一种行为

动作方法时实现这种行为的代码

动作调用其的作用是实现对一个动作的调用,而控制器中才是实现这个动作的动作方法。

即动作名与方法名默认情况下对应,但也可以让他们不同。

一个自定义动作调用器

public class CustomActionInvoker : IActionInvoker{

        public bool InvokeAction(ControllerContext controllerContext, string actionName){

            if (actionName == "Index"){

                controllerContext.HttpContext.Response.Write("This is output from the Index Action");

                return true;

            }

            else {

                return false;

            }

         }

    }

这个动作调用器并不关心控制器类中的方法。他自己处理动作。如果true则Response.Write如果false则404

与控制器相关联的动作调用器是通过Controller.ActionInvoker属性获得的。

namespace WebApplication1.Controllers{

    public class ActionInvokerController : Controller{

        public ActionInvokerController() {

            this.ActionInvoker = new CustomActionInvoker();

        }

     }

}

在这个控制器中没有动作方法,它依靠动作调用器去处理请求并导航到ActionInvoker/Index。

备注:不建议用户实现自己的动作调用器。缺点在于缺乏可扩展性、贫乏的职责分离、而且缺乏对各种视图的支持

1.5内建动作调用器--ControllerActionInvoker

默认情况下,ControllerActionInvoker查找一个具有与请求动作同名的方法。Eg,如果路由系统产生的action值为Index那么ControllerActionInvoker将查找符合动作条件的名称为Index的方法。

1.5.1自定义动作名

ActionName特性;注意如果使用这个特性创建的视图名应与ActionName的名相同否则路由不到。

1.5.2动作方法选择

[HttpPost]

[HttpGet]

[NonAction]:不会被暴露成一个外部可用的动作

1.5.3自定义动作方法选择器

namespace System.Web.Mvc{

    //     表示一个特性,该特性用于影响操作方法的选择。

    public abstract class ActionMethodSelectorAttribute : Attribute

    {

        // 摘要:

        //     确定操作方法选择对指定的控制器上下文是否有效。

        // 参数:

        //   controllerContext:

        //     控制器上下文。

        //   methodInfo:

        //     获取运用了选择器的方法信息

        // 返回结果:

        //     如果操作方法选择对指定的控制器上下文有效,则为 true;否则为 false。

        public abstract bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo);

    }

}

自定义方法选择器

/// <summary>

    /// 是否是本地请求

    /// </summary>

    public class LocalAttribute : ActionMethodSelectorAttribute

    {

        public override bool IsValidForRequest(ControllerContext controllerContext, MethodInfo methodInfo)

        {

            return controllerContext.HttpContext.Request.IsLocal;

        }

}

1.5.4处理位置动作

如果动作调用其找不到一个要调用的动作方法,便从他的InvokeAction方法返回false。当这种请求发生时,Controller类会调用它的HandleUnknownActiopn()。默认情况下,这个方法将一个404返回给浏览器。

此时如果想做一些特殊的事情,可以在控制器类中重写HandleUnknownAction()

public class HomeController : Controller

    {

        protected override void HandleUnknownAction(string actionName)

        {

            Response.Write("aaaaaaaaaaaaaaa");

        }

}

1.6用特殊控制器改善性能

MVC框架提供两种可以改善MVC web应用程序性能的特殊控制器。

1.6.1使用无会话控制器

默认情况下,控制器支持会话状态,这可以用来跨请求地存取数据值,使MVC程序员的工作更轻松。创建和维护会话状态是一个棘手的过程,必须对数据进行存储和接收,且必须对会话进行管理,以使他们能适当地终止。会话数据会消耗服务器内存或存储单元空间,而且多个web服务器之间的数据同步的需求,使得在运行一个大型应用程序的多个服务器上运行应用程序更加困难。

为了简化会话状态,asp.net对一个给定的会话在某一时刻只处理一个查询。如果客户端形成多个重叠请求,他们将被排成队列。并由服务器依序处理。好处:不需要担忧多个请求对同一暑假进行修改的情况,缺点:得不到所希望的请求吞吐量

并非所有控制器都需要这种会话状态特性。在这种情况下,能够改善应用程序的性能,而又避免了棘手的会话状态维护工作。这可以通过无会话控制器来实现。它与规则控制器一样,但有两个方面不同:在把他们用于处理一个请求时,MVC框架不加载或不存储会话状态;重叠请求可以同时处理

①在自定义IControllerFactory中管理会话状态:

在GetControllerSessionBehavior()中会返回SessionStateBehavior枚举值用于管理会话状态

②DefaultControllerFactory管理会话状态

当使用内建的控制器工厂时,可以将SessionState注解属性运用于每个控制器类,以便对控制器的会话状态进行控制

 

1.6.2使用异步控制器

核心ASP.NET平台维护着一个用来处理客户端请求的.NET线程池--工作线程池,而这些县城叫做工作线程。当接收到一个请求时,将占用线程池中的一个工作线程,以进行这个请求的处理工作。当请求处理完毕后,该工作线程被返回给线程池,以便用于新请求的处理。对ASP.NET应用程序使用线程池有两个关键好处:

  ①通过重用工作线程,避免了每次处理一个请求时,都要new一个新线程的开销

  ②通过具有固定数目的可用工作线程,避免了超出服务器处理能力的并发请求情况。

在请求可以被短时间处理完毕的情况下,工作线程池会工作的最好。这也是大多MVC应用程序的情况。但如果有一些依赖于其他服务器,且占用较长时间才能完成的动作,那么可能会遇到所有工作线程都别绑定于等待其他系统完成其工作的情况。

此刻服务器有能力做更多的工作,毕竟这只是在等待,只占用很少资源,但因为所有线程都被绑定,传入的请求都被排成队列。这会陷入应用程序处理停顿,而服务器大片限制的状态。

该问题的解决方案是使用异步控制器。这会提高应用程序的整体性能,但并不利于执行异步操作

备注异步控制器只能对占用I/O或占用带宽而非CPU密集型的动作有用。

CPU密集型:需要CPU高负荷运转(占用较多内存,执行大量处理)才能完成的动作

异步控制器视图解决的问题应当是线程池与所处理的请求类型之间搭配不当的情况。线程池意在确保每个请求得到一片服务器资源,但很可能最终停滞于一组无所事事的工作线程上。

如果对CPU密集型动作使用额外的后台线程,那么会因为涉及太多的并发请求而消弱服务器资源

创建异步控制器

创建异步控制器有两种方法:

①IAsyncController接口这与IController对等的异步接口,缺点显而易见。

②System.Web.Mvc.AsyncController对控制器进行派

public class RemoteDataController : AsyncController

    {

        // 在控制器中使用异步方法

        public async Task<ActionResult> Data()

        {

            string data=await Task<string>.Factory.StartNew(() => { return new RemoteService().GetRemoteData(); });

            return View((object)data);

        }

        //在后台类中实现异步方法

        public async Task<ActionResult> ConsumeAsyncMethod() {

            string data = await new RemoteService().GetRemoteDataAsync();

            return View("Data", (Object)data);

        }

    }

RemoteService类

public class RemoteService

    {

        public string GetRemoteData() {

            Thread.Sleep(5000);

            return "Hello Word";

        }

        public async Task<string> GetRemoteDataAsync() {

            return await Task<string>.Factory.StartNew(

                () =>

                {

                    Thread.Sleep(5000);

                    return "Hello word";

                });

        }

    }

两种方法效果一样,只是实现的异步方法位置不同

时间: 2024-08-24 02:21:44

Controller总结的相关文章

MVC—Controller分离

一.基础架构 二.BBlittleController中新增控制器: 同时继承Controller 三.编辑[BBLittle]下的路由配置文件(RouteConfig.cs): 添加上第二步中的命名空间: 这样基本完成,生成一下 验证通过

springMVC:modelandview,model,controller,参数传递

转载:http://blog.csdn.net/wm5920/article/details/8173480 1.web.xml 配置: copy <> ></> ></> > >> ></> ></> > ></> </> <> ></> ></> </> 这样,所有的.htm的请求,都会被Dispatche

DAO层,Service层,Controller层、View层介绍

来自:http://jonsion.javaeye.com/blog/592335 DAO层 DAO 层主要是做数据持久层的工作,负责与数据库进行联络的一些任务都封装在此,DAO层的设计首先是设计DAO的接口,然后在Spring的配置文件中定义此 接口的实现类,然后就可在模块中调用此接口来进行数据业务的处理,而不用关心此接口的具体实现类是哪个类,显得结构非常清晰,DAO层的数据源配置,以及 有关数据库连接的参数都在Spring的配置文件中进行配置. Service层 Service 层主要负责业

Spring MVC中 controller方法返回值

1.返回ModelAndView 定义ModelAndView对象并返回,对象中可添加model数据.指定view 2.返回String 1.表示返回逻辑视图名 model对象通过 model.addAttribute("xxx",model)进行设定 2.redirect重定向: redirect重定向特点:浏览器地址栏中的url会变化.修改提交的request数据无法传到重定向的地址.因为重定向后重新进行request(request无法共享) 3.forward页面转发: 通过f

ui-router(三)controller与template

这篇就是在以前的基础上,把客户端angular.js 负责的部分整体串起来演示一下. 我们按照angular执行顺序来做前提准备: (1)Client 根目录下 index.html 首先加载angular.js 和 ui-router.js 文件 <script src="http://cdn.bootcss.com/angular.js/1.3.8/angular.min.js"></script> <script src="./vender

通过$broadcast或$emit在子级和父级controller之间进行值传递

1 通过$broadcast或$emit在controller之间进行值传递,不过这些controller必须是子级或者父级关系, 2 $emit只能向父级parent controller传递事件event与数据data,$broadcast只能向子级child controller传递event与data,$on用于接收event与data. 3 <script> 4 var myapp=angular.module('myapp',[]); 5 myapp.controller('Sel

编写Spring MVC Controller

1.映射请求 在POJO类定义处标注@Controller,再通过<content:component-scan /...>扫描相应的类包,即可使POJO类成为一个能处理HTTP请求的控制器. 如何将请求映射到对应的控制器的方法中是Spring MVC框架最重要的任务之一,这项任务由@RequestMapping注释承担. 例子1: 1 @Controller 2 public class UserController{ 3 4 @RequestMapping(value="/use

USB device &amp; USB controller &amp; USB passthrough

近期往 openstack 里倒腾 USB passthrough[1],遂把 USB 知识做较为全面的整理,以供分享. USB device 什么是 USB device, 上图机智的小萌狗就是 USB device,你的鼠标是 USB device, 键盘是 USB device,U 盘更是典型的 USB device.说了这么多例子,还是得用一个专业的名词一语概之,所谓 USB,即是 Universal Serial Bus(通用串行总线),它是用来连接 USB device 和计算机,从

Spring MVC @RequestMapping Annotation Example with Controller, Methods, Headers, Params, @RequestPar

Spring MVC @RequestMapping Annotation Example with Controller, Methods, Headers, Params, @RequestParam, @PathVariable Pankaj July 4, 2014 Spring @RequestMapping is one of the most widely used Spring MVC annotation.org.springframework.web.bind.annotat

asp.ne中使用ajax和controller进行通信问题记录

为了页面显示和后端处理分离,使用了html+ajax+mvc的形式进行处理. 在这其中遇到的问题记录: 1. 在使用ajax向controller请求数据的时候,"get"方法会缓存上一次的请求,导致controller方法不能被debug跟踪到,开始以为是vs出错了,到后来才搞清楚. 解决方法:请求controller路径时加上随机数,或者使用"post"方法. 2. 在使用"POST"方法时,IE11要小心处理,因为ie会出现怎么都执行不了的