ASP.NET MVC 5 Controller Extensibility

 

Creating a Custom Controller Factory

Create a custom controller factory by implementing IControllerFacotry interface and register it in Application_Start method of Global.asax file.

    public class TestCustomControllerFactory: IControllerFactory
    {
        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            Type targetType = null;
            switch (controllerName)
            {
                case "Test":
                    targetType = typeof(TestController);
                    break;
                default:
                    requestContext.RouteData.Values["controller"] = "Test";
                    targetType = typeof(TestController);
                    break;
            }
            return targetType == null ? null : (IController)DependencyResolver.Current.GetService(targetType);
        }

        public SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
        {
            return SessionStateBehavior.Default;
        }

        public void ReleaseController(IController controller)
        {
            IDisposable dispose = controller as IDisposable;
            if (dispose != null)
            {
                dispose.Dispose();
            }
        }
    }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new Infrastructure.TestCustomControllerFactory());
        }

Working with the Built-in Controller Factory

DefaultControllerFactory is the built-in controller facotry class, it maintains a list of classes which meet following criteria to create controller instance:

  • The class must be public.
  • The class must be concrete (not abstract).
  • The class must not take generic parameters.
  • The name of the class must end with Controller.
  • The class must implement the IController interface.

This is convension-over-configuration pattern.

Prioritizing Namespaces

Customizing DefaultControllerFactory Controller Instantiation

There are a number of ways to customize how the DefaultControllerFactory class instantiates controller objects.

Using the Dependency Resolver

The DefaultControllerFacotry call IDependencyResolver.GetService to create controller instance, NinjectDependencyResolver implement IDependencyResolver, which gives you the opportunity to resolve and inject any dependencies.

Using a Controller Activator

You can also introduce DI into controllers by creating a controller activator. You create this activator by implementing the IControllerActivator interface.

    public class CustomControllerActivator : IControllerActivator
    {
        public IController Create(RequestContext requestContext, Type controllerType)
        {
            // Do anything you want here
            return (IController)DependencyResolver.Current.GetService(controllerType);
        }
    }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new Infrastructure.CustomControllerActivator()));
        }
Overriding DefaultControllerFactory Methods

You can override methods in the DefaultControllerFactory class to customize the creation of controllers.

    public class CustomDefaultControllerFactory: DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            // Do anything you want
            return (IController)DependencyResolver.Current.GetService(controllerType);
        }
    }
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new Infrastructure.CustomDefaultControllerFactory());
        }

Creating a Custom Action Invoker

If you derived your controller from the Controller class, then this is the responsibility of an action invoker. Action invokers are part of the functionality included in the Controller class. (If you create a controller directly from the IController interface, then you are responsible for executing the action yourself.)

An action invoker implements the IActionInvoker interface, the result type is a bool: a value of true indicates that the action was found and invoked and false indicates that the controller has no matching action.

    public class CustomActionInvoker: IActionInvoker
    {
        public bool InvokeAction(ControllerContext controllerContext, string actionName)
        { 
            // Code to execute action methods in controller
            if (actionName == "Index")
            {
                controllerContext.HttpContext.Response.Write("Response from Index action method");
                return true;
            }
            else
            {
                return false;
            }
        }
    }

The action invoker associated with a controller is obtained through the Controller.ActionInvoker property. This means that different controllers in the same application can use different action invokers.

    public class TestController : Controller
    {
        public TestController()
        {
            this.ActionInvoker = new CustomActionInvoker();
        }
    }

Using the Built-in Action Invoker

The built-in action invoker, which is the ControllerActionInvoker class, has some sophisticated techniques for matching requests to actions.

Using a Custom Action Name

Usually, the name of an action method determines the action that it represents. The Index action method services requests for the Index action. You can override this behavior using the ActionName attribute.

Using Action Method Selection

There are built-in attributes that work as selectors for the different kinds of HTTP requests: HttpPost for POST requests, HttpGet for GET requests, HttpPut for PUT requests, and so on. Another built-in attribute is NonAction, which indicates to the action invoker that a method that would otherwise be considered a valid action method should not be used.

Creating a Custom Action Method Selector

Action method selectors are derived from the ActionMethodSelectorAttribute class, it returns true from IsValidForRequest if the method is able to process a request, and false otherwise.

    public class LocalAttribute : ActionMethodSelectorAttribute
    {
        public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
        {
            return controllerContext.HttpContext.Request.IsLocal;
        }
    }

Handling Unknown Actions

You can overriding the HandleUnknownAction method of Controller class.

Improving Performance with Specialized Controllers

Using Sessionless Controllers

Not all controllers need the session state features. In such cases, you can improve the performance of your application by avoiding work involved in maintaining session state. You do this by using sessionless controllers. These are just like regular controllers, with two exceptions: the MVC Framework will not load or store session state when they are used to process a request, and overlapping requests can be processed simultaneously.

    [SessionState(System.Web.SessionState.SessionStateBehavior.Disabled)]
    public class AccountController : BaseController
    {
        public ActionResult Login(string returnUrl)
        {
            LoggerManager.DebugInfo.Info("Login Action");
            ViewBag.ReturnUrl = returnUrl;
            return View();
        }
    }

When session state is Disabled, the HttpContext.Session property returns null.

Using Asynchronous Controllers

Asynchronous controllers are useful only for actions that are I/O- or network-bound and not CPU-intensive. The problem you are trying to solve with asynchronous controllers is a mismatch between the pool model and the type of request you are processing.

        public async Task<ActionResult> GetData()
        {
            string data = await Task<string>.Factory.StartNew(() =>
            {
                Thread.Sleep(5000);
                return "hello";
            });
            return View((object)data);
        }

 

转载于:https://www.cnblogs.com/liangzi4000/p/6995627.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值