6

我的主ASP.NET MVC组合应用程序使用全局Unity容器来注册类型。该应用程序将控制器工厂设置为使用此全局容器。我想对此进行重构,使得每个便携式区域都利用其自己的子Unity容器,以便不同区域可以以各种方式实现接口。看起来我需要为每个区域使用不同的ControllerFactory。考虑到下面的所有工厂都设置了工厂,我将如何实现这一目标?特定可移植区域的ControllerFactory

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

回答

11

您可以使用一个MasterControllerFactory,其中包含每个区域的所有IControllerFactory实现,并知道哪个工厂可以构建哪个工厂。这实际上允许您为任何变体选择不同的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

我不认为你可以为每个区域不同的工厂,但是你可以在你的一个工厂,把控制器置于不同的容器中,根据面积。我认为但不知道,你可以通过查询此发现在你的工厂CreateController方法您所在的地区:

requestContext.RouteData.DataTokens["area"]; 

其中requestContext传递给CreateController作为参数。

+0

哦,是的,你可以;-) – smartcaveman 2011-03-20 06:25:36

+0

@smartcaveman:谢谢你离开这个评论 - 通过这样做你让我1)学习新的东西2)upvoting你=) – 2011-03-21 03:38:17