6

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

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

2 回答 2

11

您可以使用MasterControllerFactory包含IControllerFactory每个区域的所有实现的 a,并且知道哪个工厂可以构建哪个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);
    }
}

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

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

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

于 2011-03-20T06:22:33.847 回答
-1

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

requestContext.RouteData.DataTokens["area"];

where作为参数requestContext传递给。CreateController

于 2011-03-18T01:54:27.243 回答