我有一些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上的例子,似乎都忽略了依赖关系的发布。
谢谢!
答案 0 :(得分:2)
我有一些类似的问题,但使用Unity代替Castle Windsor。
我的要求:
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);
}
}