适用于SignalR和Castle Windsor的Hub依赖生命周期管理

时间:2014-02-23 11:21:33

标签: inversion-of-control signalr castle-windsor signalr-hub

我有一些SignalR集线器,可能需要访问一些瞬态和单独的依赖项。挂起Hub的创建很容易并且工作得很好但是SignalR在创建的Hub上执行自己的Dispose()调用,而不是通知依赖解析器并让它参与处理。

如果依赖项是注册单例,这不是什么大问题,但是如果它们被注册为瞬态,那么它们将永远不会被处置(如果需要的话)并且Windsor将保持它们活着直到Windsor容器是收集(当Web服务器正在关闭时)。

我看到了几种可能的处理方法...

a)这里有人指出了一种方法来将SignalR的HubDispatcher类子类化,以便它可以进行适当的处​​理。它不是SignalR的标准DependencyResolver的一部分,所以这可能很难/不可能

b)管道中其他地方的SignalR中的其他一些类可以被覆盖或轻松替换,以便我们可以继承HubDispatcher并确保使用子类。据我所知,这将是Owin中间件类HubDispatcherMiddleware。有没有办法强迫Owin不注册这个类,而是注册我自己的版本(这又使用我自己的HubDispatcher)?

c)有一种方法可以拦截SignalR在我的Hub类上进行的Dispose()调用,这样就可以调用Windsor来确保任何依赖关系被正确处理并从容器中释放

d)刻意避免使用瞬态生活方式依赖项,而是传入类型化工厂,以便我们可以通过Hub中的类型化工厂解决和释放每个依赖项

目前(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那里...... Hub类上的Dispose()也是虚拟的,而且博客帖子暗示虚拟Dispose()可能会增加一些复杂性(我不太确定多少而且我不知道对Castle的拦截器有足够的了解,无论如何都可以解决对IDisposable的失误问题。)

我很感激我为一个相当狭隘的观众写了这个问题 - 那些使用过Windsor和SignalR而不仅仅是解决依赖关系的人。我发现的每个例子,包括StackOverflow上的例子,似乎都忽略了依赖关系的发布。

谢谢!

1 个答案:

答案 0 :(得分:2)

我有一些类似的问题,但使用Unity代替Castle Windsor。

我的要求:

  • 我想避免在容器上注册单身人士。
  • 所有对象都在Hub中解析,应该在Hub destroy上处理。
  • 在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);
    }
}