2014-02-23 43 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); 
    } 
}