2015-05-28 63 views
4

在web api控制器功能裏面我使用了兩種服務,並且因爲他們做獨立的東西我希望他們使用不同的工作單元(交易)。web api控制器和城堡windsor的生活方式

所有必要的組件(工作單元,儲存庫)通過城堡溫莎與LifestylePerWebRequest注射。

從我的理解一個解決方案是使用LifeStyleScoped但我有兩個問題:

  1. 我想LifeStyleScoped只對這種特殊情況下一般不會
  2. 我無法找到如何使用一個簡單的例子LifeStyleScoped在控制器內部。

任何其他建議或代碼的例子,將不勝感激。

編輯:我沒有提到的的UnitOfWork沒有在控制器明確注入。控制器中注入兩項服務,這些服務使用通過castle windsor創建的工作單元。

public class SomeController : ApiController 
{ 
    private readonly IService _service1; 
    private readonly IService _service2; 

    public SomeController (IService service1, IService service2) 
    { 
     _service1= service1; 
     _service2= service2; 
    } 

    public IHttpActionResult SomeAction() 
    { 
     _service1.DoSomething(); 
     _service2.DoSomething(); 
    } 
} 

public Service : IService 
{ 
    public Service(IUnitOfWork uow) { 

    } 
} 

回答

4

如果您在Web API應用程序中使用Castle.Windsor,你可能已經在使用的IDependencyResolver,您可以連線爲使用溫莎自己的範圍,與此類似:

class WindsorDependencyResolver : IDependencyResolver 
{ 
    private readonly IWindsorContainer _container; 

    public WindsorDependencyResolver(IWindsorContainer container) 
    { 
     _container = container; 
    } 

    public object GetService(Type t) 
    { 
     return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null; 
    } 

    public IEnumerable<object> GetServices(Type t) 
    { 
     return _container.ResolveAll(t).Cast<object>().ToArray(); 
    } 

    public IDependencyScope BeginScope() 
    { 
     return new WindsorDependencyScope(_container); 
    } 

    public void Dispose() 
    { 
    } 
} 

class WindsorDependencyScope : IDependencyScope 
{ 
    private readonly IWindsorContainer _container; 
    private readonly IDisposable _scope; 

    public WindsorDependencyScope(IWindsorContainer container) 
    { 
     _container = container; 
     _scope = container.BeginScope(); 
    } 

    public object GetService(Type t) 
    { 
     return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null; 
    } 

    public IEnumerable<object> GetServices(Type t) 
    { 
     return _container.ResolveAll(t).Cast<object>().ToArray(); 
    } 

    public void Dispose() 
    { 
     _scope.Dispose(); 
    } 
} 

網站API將爲每個請求創建一個新的作用域,並在請求完成後處理它。因此,如果您正在使用這種技術,您可能會取消您的LifestylePerWebRequest,只需使用LifestyleScoped即可解決,因此需要爲每個組件註冊兩次。

第二個挑戰是:你如何獲得第二個獨立的工作單位?顯然,所有的強制性和可選控制器依賴性都將在同一個ILifetimeScope中隱式解析,所以只需簡單地爲第二個IUnitOfWork聲明一個構造函數依賴關係就行不通。

有很多的,你可以做到這一點的方式,但如果你準備住在一起Service Locator Anti-Pattern,你可以簡單地創建自己的範圍,像這樣:

public class SomeController : ApiController 
{ 
    private readonly IUnitOfWork _uow; 

    public SomeController (IUnitOfWork uow) 
    { 
     _uow = uow; 
    } 

    public IHttpActionResult SomeAction() 
    { 
     // Get a second UoW 
     using (var separatelyScopedResolver = GlobalConfiguration.Configuration.DependencyResolver.BeginScope()) 
     { 
      var anotherUoW = separatelyScopedResolver.GetService(typeof (IUnitOfWork)); 
      // Do something with this UoW... 
      anotherUoW.Save(); 
     } 

     // Do something with the default UoW... 
     _uow.Save(); 

     // Et cetera... 
    } 
} 
+0

謝謝你的建議和代碼樣本。一旦我重新開始工作(即明天),我會試一試,我會讓你知道那對我有用。 – Khronos

+0

請檢查我的編輯。第二個服務,因爲注入了控制器,已經使用了城堡創建的第一個工作單元。有什麼建議麼? – Khronos

+0

最簡單的解決方案是從構造函數中刪除第二個服務,並在上面的GetService調用中動態檢索它(而不是IUnitOfWork)。或者,如果這不是一次性的要求或要避免的服務定位器,你可以創建一個自定義IScopeAccessor http://docs.castleproject.org/(S(sgex5w45y1suwnquu1b0gd55))/Print.aspx?NS=Windsor&Page=Windsor.Implementing %20custom%20scope&AspxAutoDetectCookieSupport = 1 –