创建自定义控制器工厂

  • 时间:2019-07-11
  • 作者:Charles
  • 热度:167

要理解控制器工厂如何工作,最好的办法是创建一个自定义实现。但并不建议在项目中采取这种做法,因为通过内建的工厂进行扩展,有更容易的方式创建自定义行为,但这里是演示MVC框架如何创建控制器实例的一种很好的方式。控制器工厂是由IControllerFactory接口定义的,如下所示。

using System.Web.Routing;
using System.Web.SessionState;
 
namespace System.Web.Mvc
{
    public interface IControllerFactory
    {
        IController CreateController(RequestContext requestContext, string controllerName);
        SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
        void ReleaseController(IController controller);
    }
}

接下来,将创建一个简单的控制器工厂,并完成IControllerFactory接口中各个方法的实现。创建一个

Infrastructure文件夹,并创建一个新的名称为CustomControllerFactory.cs的类文件,如下所示。

using ContorllerExtensibility.Controllers;
using System;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.SessionState;
 
namespace ContorllerExtensibility.Infrastructure
{
    public class CustomContorllerFactory:IControllerFactory
    {
        public IController CreateController(RequestContext requestContext,string controllerName)
        {
            Type targetType = null;
            switch (controllerName.ToLower())
            {
                case "product":
                    targetType = typeof(ProductController);
                    break;
                case "customer":
                    targetType = typeof(CustomerController);
                    break;
                default:
                    requestContext.RouteData.Values["controller"] = "Product";
                    targetType = typeof(ProductController);
                    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 disposable = controller as IDisposable;
            if (disposable!=null)
            {
                disposable.Dispose();
            }
        }
    }
}

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

本例中,只有两个控制器,作为最简单直接的演示目的,打算直接对它们进行实例化,即将类名强行写入控制器工厂,对于实际项目而言,这是不可取的。

CreateController方法的目的是,创建能够对当前请求进行处理的控制器实例。至于该怎么做,没有任何限制。唯一的规则是,作为该方法的结果,必须返回一个IController接口的对象。

处理备用控制器

自定义控制器工厂必须返回IController接口的一个实现,以其作为CreateController方法的返回结果,否则会向用户显示错误。这意味着,当处理的请求不以项目中的任何一个控制器为目标时,需要有一个备用位置。读者可以创建任何自己喜欢的策略来处理这种情况。例如,可以定义一个特定的控制器来渲染错误消息,或是像本例这样,将请求映射到一个已经存在的控制器。

实例化控制器类

如何对控制器进行实例化,没有特别的规则,但使用依赖性解析是一个良好做法。它能够在自定义控制器工厂中专注于请求与控制器类之间的映射,而将依赖性注入这样的问题留下来单独进行处理,并用于整个应用程序。从以下代码可以看出如何使用DependencyResolver类去创建控制器实例。

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

静态的DependencyResolver.Current属性返回IDependencyResolver接口的实现,该接口定义了GetService方法,为方法传递的是一个System.Type对象,又转而得到它的一个实例。GetService方法还有一个强类型的版本,但是因为事先不知道要处理的是什么类型,因此,这里只能使用这个返回Object的版本,然后将它明确地转换成IController。

实现其他接口方法

IControllerFactory接口中的另外两个方法如下。

GetControllerSessionBehavior方法由MVC框架用来确定是否应该为控制器维护会话数据。

当不再需要CreateController方法创建的控制器对象时,会调用ReleaseController方法,以便释放安歇可以被释放的资源。

注册自定义控制器工厂

通过ControllerBuilder类,可以告诉MVC框架使用这个自定义控制器工厂。在应用程序启动时,必须注册自定义控制器工厂,即在Global.asax.cs文件中使用Application_Start方法,如下所示。

using ContorllerExtensibility.Infrastructure;
using System.Web.Mvc;
using System.Web.Routing;
 
namespace ContorllerExtensibility
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new CustomContorllerFactory());
        }
    }
}

一旦注册了控制器工厂,将由它负责处理应用程序接收到的所有请求。



博主声明

1、本博客主要为原创文章,转载请注明出处。

2、部分文章来自网络,已注明出处,如有侵权请与本人联系。

3、如果文章内容有误,或者您有其他更好的意见、建议请给我留言,我会及时处理!