【问题标题】:ControllerFactory for specific portable area特定便携式区域的 ControllerFactory
【发布时间】:2011-03-17 21:37:24
【问题描述】:

我的主要 ASP.NET MVC 复合应用程序使用全局 Unity 容器来注册类型。该应用程序将控制器工厂设置为使用此全局容器。我想对此进行重构,以便我的每个可移植区域都利用它自己的子 Unity 容器,以便不同的区域可以以不同的方式实现接口。似乎我需要每个区域有一个不同的 ControllerFactory 。鉴于以下内容为所有人设置了工厂,我将如何做到这一点?

ControllerBuilder.Current
    .SetControllerFactory(/* controller factory with global unity container */);

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-2 dependency-injection unity-container controller-factory


    【解决方案1】:

    您可以使用包含每个区域的所有IControllerFactory 实现的MasterControllerFactory,并且知道哪个工厂可以构建哪个RequestContext。这实际上允许您为任何变化选择不同的 ControllerFactory,而不仅仅是按区域。以下是它的工作原理:

    所有区域控制器工厂实现都必须实现 IFilteredControllerFactory 而不是 IControllerFactory。这里是:

    public interface IFilteredControllerFactory:IControllerFactory
    {
        bool CanHandle(RequestContext requestContext);
    }  
    

    根据区域名称进行过滤的实现示例如下所示:

    public class Area51ControllerFactory:IFilteredControllerFactory
    {
        public bool CanHandle(RequestContext requestContext)
        {
            return requestContext.RouteData.DataTokens["area"].ToString().ToLowerInvariant() == "area51";
        }
        public IController CreateController(RequestContext requestContext, string controllerName)
        {
            // create a controller...
        }
    
        public void ReleaseController(IController controller)
        {
            // release the controller...
        }
    
    }
    

    然后你需要MasterControllerFactory,它看起来像这样:

    public class MasterControllerFactory : DefaultControllerFactory
    {
        private readonly List<IFilteredControllerFactory> _slaveFactories;
        public MasterControllerFactory()
        {
            _slaveFactories = new List<IFilteredControllerFactory>();
        }
        public void RegisterFactory(IFilteredControllerFactory slaveFactory)
        {
            if(slaveFactory!=null && !_slaveFactories.Contains(slaveFactory))
            {
                _slaveFactories.Add(slaveFactory);
            }
        }
    
        public override IController CreateController(RequestContext requestContext, string controllerName)
        {
            var factory = _slaveFactories.FirstOrDefault(x => x.CanHandle(requestContext));
            if(factory!=null)
            {
                return factory.CreateController(requestContext, controllerName);
            }
            return base.CreateController(requestContext, controllerName);
        }
    
        public override void ReleaseController(IController controller)
        {
            bool released = false;
            if (controller is Controller)
            {
                var requestContext = ((Controller) controller).ControllerContext.RequestContext;
                var factory = _slaveFactories.FirstOrDefault(x => x.CanHandle(requestContext));
                if (factory != null)
                {
                    factory.ReleaseController(controller);
                    released = true;
                }
            }
            if(!released)base.ReleaseController(controller);
        }
    }
    

    global.asax 的 Application_Start 中,您仍然需要设置所有内容,但这很容易。

    var masterControllerFactory = new MasterControllerFactory();
    masterControllerFactory.Register(new Area51ControllerFactory());
    ControllerBuilder.Current.SetControllerFactory(masterControllerFactory);
    

    显然,您可以通过多种方式对其进行调整,以最适合您的编码风格和应用程序架构。

    【讨论】:

      【解决方案2】:

      我不认为每个区域可以有不同的工厂,但是您可以在单个工厂中,根据区域将控制器放入不同的容器中。我认为但不确定,您可以通过以下查询在工厂的 CreateController 方法中找到您的区域:

      requestContext.RouteData.DataTokens["area"];
      

      其中requestContext 作为参数传递给CreateController

      【讨论】:

      • @smartcaveman:感谢您留下此评论 - 通过这样做,您让我 1) 学习新东西 2) 支持您 =)
      猜你喜欢
      • 1970-01-01
      • 2023-04-07
      • 2012-08-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多