Proper Hub dependency lifetime management for SignalR and Castle Windsor

后端 未结 1 934
暗喜
暗喜 2021-02-03 19:15

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 it

相关标签:
1条回答
  • 2021-02-03 19:50

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

    My requirements:

    • 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());
    

    This is my solution:

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

    Dependency resolver implementation:

    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);
        }
    }
    
    0 讨论(0)
提交回复
热议问题