对SignalR和Castle Windsor进行适当的Hub依赖项生命周期管理 [英] Proper Hub dependency lifetime management for SignalR and Castle Windsor

查看:109
本文介绍了对SignalR和Castle Windsor进行适当的Hub依赖项生命周期管理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些SignalR集线器,可能需要访问一些瞬态和单例依赖项。挂接Hub的创建很容易并且可以正常工作,但是SignalR会对创建的Hub进行自己的Dispose()调用,而不是通知依赖项解析器并让其参与处理。

I have some SignalR hubs which may need to access some transient and singleton dependencies. Hooking the creation of the Hub is easy and works just fine however SignalR does its own Dispose() call on the created Hub rather than notifying the dependency resolver and letting it get involved in the disposal.

如果依赖项被注册为单例,这没什么大不了的,但是如果将它们注册为瞬态,则它们将永远不会被处置(如果需要),并且温莎将使它们保持生存直到温莎

This isn't such a big deal if the dependencies are registered singletons, but if they're registered as transients then they'll never get disposed (if that was required) and Windsor will keep them alive until the Windsor container is collected (when the web server is shutting down anyway).

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

I see several possible ways of handling this...

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

a) Someone here points out a way to subclass SignalR's HubDispatcher class so that it can do proper disposal. It's not part of SignalR's standard DependencyResolver so this might be difficult / impossible

b)SignalR中其他一些类,可以在管道中的其他地方覆盖或轻松替换,以便我们可以将HubDispatcher子类化,并确保使用了子类。据我所知,这必须是Owin中间件类HubDispatcherMiddleware。有什么方法可以强迫Owin不注册此类,而是注册自己的版本(依次使用我自己的HubDispatcher)?

b) Some other class in SignalR, elsewhere in the pipeline, can be overridden or easily replaced so that we could subclass HubDispatcher and ensure that subclass is used. From what I can tell this would have to be the Owin middleware class HubDispatcherMiddleware. Is there some way to force Owin to not register this class and instead register my own version of this (which in turn uses my own HubDispatcher)?

c)拦截SignalR在我的Hub类上进行的Dispose()调用,以便可以回调用Windsor以确保正确处置所有依赖项并将其从容器中释放

c) There's some way of intercepting the Dispose() call made by SignalR on my Hub classes so that a call could be made back to Windsor to ensure any dependencies are properly disposed and released from the container

d)勤奋地避免使用短暂的生活方式依赖关系,而是传入类型化工厂,以便我们可以通过集线器内的类型化工厂来解析和释放每个依赖项

d) Studiously avoid using transient lifestyle dependencies and instead pass in typed factories so that we can resolve and release each dependency via the typed factory within the Hub

d)是我唯一知道的方法。 (a)或(b)会很棒。 (c)大部分由该帖子覆盖 http:// kozmic .net / 2010/01/27 / transparently-releasing-components-in-windsor / ,但是,拦截器要求通过IDisposable调用Dispose()。 SignalR的HubDispather类对集线器处置的实现是

At the moment (d) is the only one I know how to do. (a) or (b) would be great. (c) is mostly covered by this post http://kozmic.net/2010/01/27/transparently-releasing-components-in-windsor/, however, the interceptor requires that Dispose() be called via IDisposable. SignalR's HubDispather class' implementation of hub disposal is

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

在此处不强制转换为IDisposable ... Also Dispose( )上的Hub类是虚拟的,并且该博客文章暗示虚拟的Dispose()可能会增加一些复杂性(我不太清楚城堡的拦截器的数量,而且我还不够了解,以及是否将丢失的内容强制转换为IDisposable

No casting to IDisposable there... Also Dispose() on the Hub class is virtual and that blog post implies that a virtual Dispose() could add some complexity (I'm not quite sure how much and I don't know enough about Castle's interceptors and whether or not that missing cast to IDisposable can be worked around anyway).

我很感激我已经为相当狭窄的受众群体写了这个问题-那些使用Windsor AND SignalR并不仅关心解决问题的人依赖性。我发现的每个示例,包括StackOverflow上的示例,似乎都忽略了依赖项的发布。

I appreciate I've written this question for a fairly narrow audience - those who have used Windsor AND SignalR and care about more than just resolving dependencies. Every example I've found, including those on StackOverflow, seems to just ignore the release of dependencies.

谢谢!

推荐答案

我遇到了类似的问题,但是使用Unity而不是温莎城堡。

I've had a bit similar problem but with Unity instead of Castle Windsor.

我的要求:


  • 我想避免在容器上进行单例注册。

  • 所有对象都在Hub中解析,应将其丢弃

  • 在Web Api和SignalR中重复使用注册。

  • 对象生存期由 HierarchicalLifetimeManager -子容器解析和管理单独的对象实例。像这样注册:

  • I wanted to avoid singleton registrations on the container.
  • All objects are resolved in Hub and should be disposed on Hub destruction.
  • Registrations reused across Web Api and SignalR.
  • Object lifetime is managed by HierarchicalLifetimeManager - child containers resolve and manage separate object instances. Registered like this:
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和依赖解析器配置:

SignalR and dependency resolver configuration:

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);
    }
}

这篇关于对SignalR和Castle Windsor进行适当的Hub依赖项生命周期管理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆