2014-02-23 44 views
35

我有一些SignalR集線器可能需要訪問一些瞬態和單例依賴關係。鉤住Hub的創建非常簡單,而且工作得很好,但SignalR在創建的Hub上執行自己的Dispose()調用,而不是通知依賴關係解析器並讓它參與處理。適用於SignalR和Castle Windsor的集線器依賴關係生存期管理

如果依賴項是已註冊的單身人士,這並不是什麼大不了的事情,但是如果他們被註冊爲瞬變,那麼他們將永遠不會被處置(如果需要的話),並且Windsor會讓他們活着直到Windsor容器被收集(當Web服務器正在關閉時)。

我看到處理該幾種可能的方式...

一)有人在這裏指出的方式來繼承SignalR的HubDispatcher類,以便它可以做適當的處理。它不是SignalR的標準DependencyResolver的一部分,所以這可能很難/不可能

b)SignalR中的其他一些類,在管道中的其他地方,可以重寫或輕易替換,以便我們可以繼承HubDispatcher並確保使用子類。從我可以告訴的這將是歐文中間件類HubDispatcherMiddleware。有沒有辦法強制Owin不註冊這個類,而是註冊我自己的這個版本(反過來使用我自己的HubDispatcher)?

三)有攔截SignalR我集線器類所做的Dispose()調用,這樣一個電話可以作出回溫,以確保任何依賴是妥善處置,並從容器

d公佈的一些方法)儘量避免使用短暫的生活方式依賴,而是通過打字工廠,以便我們可以通過集線器內的打字工廠來解決和釋放每個依賴關係。目前(d)是我唯一知道該怎麼做的人。 (a)或(b)會很好。 (c)主要由http://kozmic.net/2010/01/27/transparently-releasing-components-in-windsor/這個帖子覆蓋,但是,攔截器要求通過IDisposable調用Dispose()。 SignalR的HubDispather類的實現樞紐處置是

private static void DisposeHubs(IEnumerable<IHub> hubs) 
{ 
    foreach (var hub in hubs) 
    { 
     hub.Dispose(); 
    } 
} 

沒有鑄造的IDisposable還有...還有的Dispose()在集線器類是虛擬和博客帖子意味着一個虛擬的Dispose()可能會增加一些複雜性(我不太清楚Castle的攔截器有多少,我對這些攔截器的知識還不夠多,無論是否丟失到IDisposable都可以解決。

我很欣賞我爲一個相當狹窄的受衆撰寫了這個問題 - 那些使用Windsor AND SignalR並且關心的不僅僅是解決依賴問題。我發現的每個示例(包括StackOverflow上的示例)似乎都忽略了依賴關係的發佈。

謝謝!

+2

當圖書館聲稱是IoC友好但只支持Resolve()而不支持Release()時,這令人沮喪。 –

+0

絕對......我正在考慮編譯自己的SignalR副本,如果我可以編寫GitHub的東西,就可以創建某種拉請求,並推理代碼所需的(非常輕微的)更改。 –

+1

對於其他誰發現這一點,截至2014年2月,官方建議在https://github.com/SignalR/SignalR/issues/2908。未來的版本應該改進。在此期間,我可能只會編輯自己的稍微調整過的副本。 –

回答

2

我已經有點類似的問題,但與團結,而不是溫莎城堡。

我的要求:

  • 我想避免在容器上單登記。
  • 所有對象都在Hub中解析,並應在Hub銷燬時處理。
  • 跨Web Api和SignalR重複使用註冊。
  • 對象生命週期由HierarchicalLifetimeManager管理 - 子容器解析和管理單獨的對象實例。註冊這樣的:
container.RegisterType<IMessageService, MessageService>(new HierarchicalLifetimeManager()); 

這是我的解決方案:

[HubName("exampleHub")] 
public class ExampleHub : Hub 
{ 
    IUnityContainer _container; 

    public CarrierApiHub(IUnityContainer container) // container itself injected in hub 
    { 
     _container = container.CreateChildContainer(); // child container derived from the main container. 
    } 

    public async Task<int> UnreadMessagesCount() 
    { 
     // Here i'm resolving instance of IMessageService which depends on 
     // other registrations specified on the container. Full object graph 
     // is constructed and destroyed on hub disposal. 
     var messageSvc = _container.Resolve<IMessageService>(); 
     return await messageSvc.CountUnreadOf(UserId); 
    } 

    protected override void Dispose(bool disposing) 
    { 
     _container.Dispose(); // child container destroyed. all resolved objects disposed. 
     base.Dispose(disposing); 
    } 

    private int UserId 
    { 
     get 
     { 
      // only an example 
      var claim = ((ClaimsPrincipal)Context.User).GetClaim("user_id"); 
      return int.Parse(claim.Value); 
     } 
    } 
} 

SignalR和依賴解析器配置:

public static class ConfigureSignalR 
{ 
    public static void Initialize(UnityContainer unityContainer, IAppBuilder app) 
    { 
     app.Map("/signalr", map => 
     { 
      var resolver = new AppSignalRDependencyResolver(unityContainer); 

      map.UseCors(CorsOptions.AllowAll); 

      var hubConfiguration = new HubConfiguration 
      { 
       EnableJavaScriptProxies = false, 
       EnableJSONP = true, // Required for IE 9 (supports only polling) 
       Resolver = resolver 
      }; 

      map.RunSignalR(hubConfiguration); 
     }); 
    } 
} 

依賴解析器實現:

public class AppSignalRDependencyResolver : DefaultDependencyResolver 
{ 
    protected IUnityContainer _container; 

    public AppSignalRDependencyResolver(IUnityContainer container) 
    { 
     if (container == null) 
     { 
      throw new ArgumentNullException("container"); 
     } 
     this._container = container.CreateChildContainer(); 
    } 

    public override object GetService(Type serviceType) 
    { 
     try 
     { 
      return _container.Resolve(serviceType); 
     } 
     catch (ResolutionFailedException) 
     { 
      return base.GetService(serviceType); 
     } 
    } 

    public override IEnumerable<object> GetServices(Type serviceType) 
    { 
     try 
     { 
      return _container.ResolveAll(serviceType).Concat(base.GetServices(serviceType)); 
     } 
     catch (ResolutionFailedException) 
     { 
      return base.GetServices(serviceType); 
     } 
    } 

    protected override void Dispose(bool disposing) 
    { 
     _container.Dispose(); 
     base.Dispose(disposing); 
    } 
}