适用于SignalR和Castle Windsor的Hub依赖性生命周期pipe理
我有一些SignalR集线器可能需要访问一些瞬态和单身的依赖关系。 钩住Hub的创build很容易,而且工作得很好,但是SignalR在创build的Hub上自己调用Dispose(),而不是通知依赖parsing器并让它参与处理。
如果依赖关系被注册为单身人士,这并不是什么大不了的事情,但是如果他们被注册为瞬间的话,那么他们将永远不会被处置(如果需要的话),温莎会保留他们,直到收集Windsor容器Web服务器正在closures)。
我看到几种可能的方式来处理这个…
a)这里有人指出了一种方法来划分SignalR的HubDispatcher类的子类,以便它可以做适当的处理。 这不是SignalR的标准DependencyResolver的一部分,所以这可能是困难的或不可能的
b)SignalR中的其他一些类,在pipe道中的其他地方,可以重写或轻易replace,以便我们可以inheritanceHubDispatcher并确保使用子类。 从我可以告诉的是,这将是Owin中间件类HubDispatcherMiddleware。 有没有办法强制Owin不注册这个类,而是注册我自己的版本(反过来使用我自己的HubDispatcher)?
c)有一些方法可以拦截由我的Hub类上的SignalR所做的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那里…另外Dispose()在Hub类是虚拟的,并且博客文章暗示虚拟Dispose()可能增加一些复杂性(我不太确定多less和我不知道足够城堡的拦截器,无论是否丢失IDisposable的可以无论如何工作)。
我很欣赏我为一个相当狭隘的读者写了这个问题 – 那些使用过Windsor和SignalR的人,而不仅仅是解决依赖问题。 我发现的每个例子,包括StackOverflow上的例子,似乎都忽略了依赖关系的发布。
谢谢!
我有一个类似的问题,但与团结,而不是温莎城堡。
我的要求:
- 我想避免在容器上进行单身人士注册。
- 所有对象都在Hub中parsing,应该放在Hub销毁。
- 在Web Api和SignalR之间重复使用注册。
- 对象生命周期由
HierarchicalLifetimeManager
pipe理 – 子容器parsing和pipe理单独的对象实例。 像这样注册:
container.RegisterType<IMessageService, MessageService>(new HierarchicalLifetimeManager());
这是我的解决scheme:
[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和依赖关系parsing器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); }); } }
依赖parsing器的实现:
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); } }