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