我的主要ASP.NET MVC组合应用程序使用全局Unity容器来注册类型。该应用程序将控制器工厂设置为使用此全局容器。我想重构这一点,以便我的每个可移植区域都利用它自己的子Unity容器,以便不同的区域可以以不同的方式实现接口。看起来每个区域需要一个不同的ControllerFactory。鉴于以下内容为所有人设置工厂,我将如何实现这一目标?
ControllerBuilder.Current
.SetControllerFactory(/* controller factory with global unity container */);
答案 0 :(得分:11)
您可以使用包含每个区域的所有MasterControllerFactory
实施的IControllerFactory
,并知道哪个工厂可以构建哪个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);
显然,您可以通过多种方式调整这种方式,以便最好地利用您的编码风格和应用程序架构。
答案 1 :(得分:-1)
我认为您不能在每个区域拥有不同的工厂,但您可以在您的单个工厂中,根据区域将控制器放入不同的容器中。我想但不确定,您可以通过查询来查找工厂的CreateController方法中的区域:
requestContext.RouteData.DataTokens["area"];
其中requestContext
作为参数传递给CreateController
。