rba*_*all 27 c# simple-injector signalr
我认为使用我自己的IoC对SignalR非常简单,也许是; 我很可能做错了什么.这是我到目前为止的代码:
private static void InitializeContainer(Container container)
{
container.Register<IMongoHelper<UserDocument>, MongoHelper<UserDocument>>();
// ... registrations like about and then:
var resolver = new SimpleInjectorResolver(container);
GlobalHost.DependencyResolver = resolver;
}
Run Code Online (Sandbox Code Playgroud)
然后我的班级:
public class SimpleInjectorResolver : DefaultDependencyResolver
{
private Container _container;
public SimpleInjectorResolver(Container container)
{
_container = container;
}
public override object GetService(Type serviceType)
{
return _container.GetInstance(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return _container.GetAllInstances(serviceType) ?? base.GetServices(serviceType);
}
}
Run Code Online (Sandbox Code Playgroud)
最终发生的事情是我得到一个IJavaScriptProxyGenerator无法解决的错误,所以我想,我会添加注册:
container.Register<IJavaScriptProxyGenerator, DefaultJavaScriptProxyGenerator>(
ConstructorSelector.MostParameters);
Run Code Online (Sandbox Code Playgroud)
但是还有其他一些人!我到达:
container.Register<IDependencyResolver, SimpleInjectorResolver>();
container.Register<IJavaScriptMinifier, NullJavaScriptMinifier>();
container.Register<IJavaScriptProxyGenerator, DefaultJavaScriptProxyGenerator>(
ConstructorSelector.MostParameters);
container.Register<IHubManager, DefaultHubManager>();
container.Register<IHubActivator, DefaultHubActivator>();
container.Register<IParameterResolver, DefaultParameterResolver>();
container.Register<IMessageBus, InProcessMessageBus>(ConstructorSelector.MostParameters);
Run Code Online (Sandbox Code Playgroud)
这仍然给我"没有ITraceManager找到类型的注册." ......但是现在我想知道我是否正在做这件事,因为我希望我不需要重新连接SignalR所做的一切......对吗?希望?如果不是,我会继续跋涉,但我是一个SignalR和简单的注射器newb所以我想我先问.:)
附加:https://cuttingedge.it/blogs/steven/pivot/entry.php ? id = 88,因为SignalR有多个构造函数.
Nat*_*and 45
好吧,我昨天试过,我找到了解决方案.据我所知,我想在SignalR中进行依赖注入的唯一时刻是我的集线器:我不关心SignalR如何在内部工作!因此,我创建了自己的IHubActivator实现,而不是替换DependencyResolver:
public class SimpleInjectorHubActivator : IHubActivator
{
private readonly Container _container;
public SimpleInjectorHubActivator(Container container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
return (IHub)_container.GetInstance(descriptor.HubType);
}
}
Run Code Online (Sandbox Code Playgroud)
我可以像这样注册(在Application_Start中):
var activator = new SimpleInjectorHubActivator(container);
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);
RouteTable.Routes.MapHubs();
Run Code Online (Sandbox Code Playgroud)
dan*_*wig 25
想要在这里与其他答案一起投入2美分,这有助于在SignalR中使用SimpleInjector或其他IoC在依赖注入中找到自己的方式.
如果您决定使用Steven的答案,请确保在撰写根目录之前注册中心路由.该SignalRRouteExtensions.MapHubs扩展方法(又名routes.MapHubs())将调用Register(Type, Func<object>)的GlobalHost.DependencyResolver映射枢纽路由时,如果你换出DefaultDependencyResolver与史蒂芬的SimpleInjectorResolver路由映射前,你会碰上他NotSupportedException.
这是我最喜欢的.为什么?
SimpleInjectorDependencyResolver.DefaultDependencyResolver(aka GlobalHost.DependencyResolver),这意味着更少的代码.DefaultDependencyResolver它,它将"正常工作".就像Nathanael所说的那样,只有当你关心你的Hub类的依赖关系时才会这样,大多数人都可能会这样.如果你想把其他依赖注入SignalR,你可能想要接受Steven的回答.
HubSignalR有一个有趣的事情......当客户端与集线器断开连接时(例如关闭浏览器窗口),它将创建一个新的Hub类实例以便调用OnDisconnected().发生这种情况时,HttpContext.Current为null.因此,如果这Hub具有根据web请求注册的任何依赖项,则可能会出现问题.
我尝试使用Ninject和nuget上的ninject signalr依赖解析器进行SignalR依赖注入.使用此配置,在断开事件期间.InRequestScope()注入到a时,将临时创建绑定的依赖Hub项.既然HttpContext.Current是null,我想Ninject只是决定忽略它并在不告诉你的情况下创建瞬态实例.也许有一个配置设置告诉ninject警告这个,但它不是默认值.
另一方面,当一个Hub依赖于注册的实例时,SimpleInjector将抛出异常WebRequestLifestlyle:
NameOfYourHub类型的已注册委托引发了异常.NameOfYourPerRequestDependency类型的已注册委托引发了异常.YourProject.Namespace.NameOfYourPerRequestDependency注册为"PerWebRequest",但是在HttpContext的上下文之外请求实例(HttpContext.Current为null).确保在应用程序初始化阶段和在后台线程上运行时,不会解析使用此生活方式的实例.要解析后台线程上的实例,请尝试将此实例注册为"Per Lifetime Scope":https://simpleinjector.readthedocs.io/en/latest/lifetimes.html#scoped.
...注意HttpContext.Current == null,只有当我想知道SignalR请求一个Hub实例才能调用时,这个异常才会冒泡OnDisconnected().
Hub请注意,这些都不是理想的,它将取决于您的应用要求.
如果您需要非瞬态依赖项,请不要覆盖OnDisconnected()或执行与类依赖项相关的任何自定义.如果这样做,图中的每个依赖项将是一个单独的(瞬态)实例.
你需要一个混合的生活方式之间WebRequestLifestlye,要么Lifestyle.Transient,Lifestyle.Singleton或LifetimeScopeLifestyle.如果HttpContext.Current不为null,则依赖关系将仅与您通常期望的Web请求一样长.但是,当HttpContext.Current为null时,依赖关系将作为单例或在生命周期范围内瞬时注入.
var lifestyle = Lifestyle.CreateHybrid(
lifestyleSelector: () => HttpContext.Current != null,
trueLifestyle: new WebRequestLifestyle(),
falseLifestyle: Lifestyle.Transient // this is what ninject does
//falseLifestyle: Lifestyle.Singleton
//falseLifestyle: new LifetimeScopeLifestyle()
);
Run Code Online (Sandbox Code Playgroud)
LifetimeScopeLifestyle就我而言,我有一个EntityFramework DbContext依赖项.这些可能很棘手,因为它们可以在短暂登记或单身时暴露问题.在临时注册时,您可以在尝试使用附加到2个或更多DbContext实例的实体时结束异常.当注册为单身时,您最终会得到更一般的例外(不要将其注册DbContext为单身).在我的情况下,我需要DbContext生活在特定的生命周期内,在这个生命周期中,相同的实例可以在许多嵌套操作中重用,这意味着我需要LifetimeScopeLifestyle.
现在,如果您将上面的混合代码与falseLifestyle: new LifetimeScopeLifestyle()行一起使用,则在IHubActivator.Create执行自定义方法时会出现另一个异常:
NameOfYourHub类型的已注册委托引发了异常.NameOfYourLifetimeScopeDependency注册为"LifetimeScope",但实例是在生命周期范围的上下文之外请求的.确保首先调用container.BeginLifetimeScope().
您设置生命周期范围依赖项的方式如下:
using (simpleInjectorContainer.BeginLifetimeScope())
{
// resolve solve dependencies here
}
Run Code Online (Sandbox Code Playgroud)
必须在此using块中解析使用生命周期范围注册的任何依赖项.此外,如果这些依赖项中的任何一个实现IDisposable,它们将在using块的末尾被处理掉.不要试图做这样的事情:
public IHub Create(HubDescriptor descriptor)
{
if (HttpContext.Current == null)
_container.BeginLifetimeScope();
return _container.GetInstance(descriptor.HubType) as IHub;
}
Run Code Online (Sandbox Code Playgroud)
我问过史蒂文(如果你不知道的话,他也恰好是SimpleInjector的作者),他说:
那么..如果你不处理LifetimeScope,你将遇到大麻烦,所以要确保它们被处理掉.如果你不处理范围,它们将在ASP.NET中永远存在.这是因为范围可以嵌套并引用其父范围.因此,一个线程保持最活跃的内部范围(使用其缓存),并且此范围保持其父范围(具有其缓存)等等.ASP.NET池线程并且在从池中获取线程时不会重置所有值,因此这意味着所有范围都保持活动状态,并且下次从池中获取线程并启动新的生命周期范围时,您将只是创建一个新的嵌套范围,这将继续堆叠.迟早,你会得到一个OutOfMemoryException.
您不能使用它IHubActivator来限定依赖项的范围,因为它不会像Hub它创建的实例那样存在.因此,即使您将BeginLifetimeScope()方法包装在一个using块中,您的依赖项也会在Hub创建实例后立即处理.你真正需要的是另一层间接.
我非常感谢Steven的帮助,是一个命令装饰器(以及一个查询装饰器).A Hub不能依赖于每个Web请求实例本身,而必须依赖于另一个接口,其实现取决于每个请求实例.注入到Hub构造函数中的实现通过一个包装器进行修饰(通过simpleinjector),该包装器开始并处理生命周期范围.
public class CommandLifetimeScopeDecorator<TCommand> : ICommandHandler<TCommand>
{
private readonly Func<ICommandHandler<TCommand>> _handlerFactory;
private readonly Container _container;
public CommandLifetimeScopeDecorator(
Func<ICommandHandler<TCommand>> handlerFactory, Container container)
{
_handlerFactory = handlerFactory;
_container = container;
}
[DebuggerStepThrough]
public void Handle(TCommand command)
{
using (_container.BeginLifetimeScope())
{
var handler = _handlerFactory(); // resolve scoped dependencies
handler.Handle(command);
}
}
}
Run Code Online (Sandbox Code Playgroud)
...它是ICommandHandler<T>依赖于每个Web请求实例的修饰实例.有关所用模式的更多信息,请阅读本文和此内容.
container.RegisterManyForOpenGeneric(typeof(ICommandHandler<>), assemblies);
container.RegisterSingleDecorator(
typeof(ICommandHandler<>),
typeof(CommandLifetimeScopeDecorator<>)
);
Run Code Online (Sandbox Code Playgroud)
更新此答案已针对SignalR 1.0版进行了更新
这是如何IDependencyResolver为Simple Injector 构建SignalR :
public sealed class SimpleInjectorResolver
: Microsoft.AspNet.SignalR.IDependencyResolver
{
private Container container;
private IServiceProvider provider;
private DefaultDependencyResolver defaultResolver;
public SimpleInjectorResolver(Container container)
{
this.container = container;
this.provider = container;
this.defaultResolver = new DefaultDependencyResolver();
}
[DebuggerStepThrough]
public object GetService(Type serviceType)
{
// Force the creation of hub implementation to go
// through Simple Injector without failing silently.
if (!serviceType.IsAbstract && typeof(IHub).IsAssignableFrom(serviceType))
{
return this.container.GetInstance(serviceType);
}
return this.provider.GetService(serviceType) ??
this.defaultResolver.GetService(serviceType);
}
[DebuggerStepThrough]
public IEnumerable<object> GetServices(Type serviceType)
{
return this.container.GetAllInstances(serviceType);
}
public void Register(Type serviceType, IEnumerable<Func<object>> activators)
{
throw new NotSupportedException();
}
public void Register(Type serviceType, Func<object> activator)
{
throw new NotSupportedException();
}
public void Dispose()
{
this.defaultResolver.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,设计存在问题DefaultDependencyResolver.这就是为什么上面的实现不继承它,而是包装它.我在SignalR网站上创建了一个关于此的问题.你可以在这里阅读它.虽然设计师同意我的意见,但不幸的是1.0版本中没有修复该问题.
我希望这有帮助.