SimpleInjector.ActivationException 在 SignalrR 上使用简单注入器
SimpleInjector.ActivationException with Simple Injector on SignalrR
我在 Using Simple Injector with SignalR and my services are successfully resolved, not until OnDisconnected
is called on the Hub class. Then I had to follow this question 上实现了答案作为解决方法,但每当请求集线器实例时都会出现异常。
我得到异常说:
[SimpleInjector.ActivationException] The registered delegate for type ChatHub threw an exception. The ChatHub is registered as 'Hybrid Web Request / Execution Context Scope' lifestyle, but the instance is requested outside the context of a Hybrid Web Request / Execution Context Scope.
堆栈跟踪:
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstance(Type serviceType)
at QuickChat.Hubs.SimpleInjectorHubActivator.Create(HubDescriptor descriptor) in c:\Users\Peter\Documents\Visual Studio 2013\Projects\QuickChat\QuickChat\Hubs\SimpleInjectorHubActivator.cs:line 21
at Microsoft.AspNet.SignalR.Hubs.DefaultHubManager.ResolveHub(String hubName)
at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, StateChangeTracker tracker, Boolean throwIfFailedToCreate)
InnerException:
at SimpleInjector.Scope.GetScopelessInstance[TService,TImplementation](ScopedRegistration`2 registration)
at SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration`2 registration, Scope scope)
at SimpleInjector.Advanced.Internal.LazyScopedRegistration`2.GetInstance(Scope scope)
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.GetInstance()
查看下面我当前的代码配置。
集线器激活器:
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);
}
}
SimpleInjector 服务注册:
public class SimpleInjectorConfig
{
public static void Register()
{
// Create the container as usual.
var container = new Container();
var hybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new SimpleInjector.Integration.Web.WebRequestLifestyle(),
new ExecutionContextScopeLifestyle());
// Register types:
container.RegisterSingle<MembershipRebootConfiguration>(MembershipRebootConfig.Create);
container.Register<DefaultMembershipRebootDatabase>(() => new CustomMembershipRebootDatabase());
container.Register<UserAccountService>(() => new UserAccountService(container.GetInstance<MembershipRebootConfiguration>(), container.GetInstance<IUserAccountRepository>()));
container.Register<AuthenticationService, SamAuthenticationService>();
container.RegisterPerWebRequest<IUserAccountQuery, DefaultUserAccountRepository>();
container.RegisterPerWebRequest<IUserAccountRepository, DefaultUserAccountRepository>();
container.Register(() => new DataAccess.EF.DataContext(), hybrid);
container.Register<IUnitOfWork, UnitOfWork>(hybrid);
container.Register<IUserService, UserService>(hybrid);
//Register SimpleAuthentication callback provider class
container.RegisterPerWebRequest<IAuthenticationCallbackProvider, SimpleAuthenticationProviderController>();
//Register SimpleAuthentication MVC controller.
container.RegisterPerWebRequest<SimpleAuthenticationController>(
() => new SimpleAuthenticationController(container.GetInstance<IAuthenticationCallbackProvider>(), null));
// This is an extension method from the integration package.
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
// This is an extension method from the integration package as well.
container.RegisterMvcIntegratedFilterProvider();
//Enable injections to SignalR Hubs
var activator = new SimpleInjectorHubActivator(container);
container.Register<ChatHub, ChatHub>(hybrid);
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);
container.Verify();
//Set dependency resolver for MVC
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
}
Global.asax.cs:
protected void Application_Start()
{
SimpleInjectorConfig.Register();
// Register the default hubs route: ~/signalr/hubs
RouteTable.Routes.MapHubs();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}
你的混合生活方式是错误的。你应该改变谓词:
var hybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new ExecutionContextScopeLifestyle(),
new SimpleInjector.Integration.Web.WebRequestLifestyle());
提示:与其在整个组合根中重复使用该 hybrid
变量,还可以将其设置为默认作用域生活方式,如下所示:
container.Options.DefaultScopedLifestyle = hybrid;
通过这种方式,您可以将注册更改为以下内容:
container.Register<ChatHub, ChatHub>(Lifestyle.Scoped);
这使您的注册更容易、更清晰。
正如史蒂文在他的回答中所说,我的混合生活方式是错误的。我不得不改变谓词:
var hybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new ExecutionContextScopeLifestyle(),
new SimpleInjector.Integration.Web.WebRequestLifestyle());
在与 Steven GitHub 讨论了几次之后,我得出了一个结论。
我必须将我的 ChatHub
变成 Humble Object 并从中提取所有逻辑并放入一个单独的 class 中,该 class 实现一个服务接口,该接口由公开所有逻辑的方法组成最初包含在 ChatHub
public interface IChatService
{
void OnConnected(Guid userId, string connectionId, HubConnectionContext clients);
void OnDisconnected(Guid userId, string connectionId);
void Broadcast(string message, string username, HubConnectionContext clients);
}
public class ChatService : IChatService
{
private readonly IUnitOfWork _unitOfWork;
public UserChatService(IUnitOfWork unitOfWork) {
_unitOfWork = unitOfWork;
}
public void OnConnected(Guid userId, string connectionId, HubConnectionContext clients) {
//Perform other operation using _unitOfWork
}
public void OnDisconnected(Guid userId, string connectionId) {
//Perform other operation using _unitOfWork
}
public void Broadcast(string message, string username, HubConnectionContext clients) {
//Perform other operation using _unitOfWork and HubConnectionContext
//broadcast message to other connected clients
clients.others.broadcast(message);
}
}
HubConnectionContext
对我来说真的像是运行时数据,所以我决定将它作为参数传递给方法。
有了这个,我的集线器 ChatHub
看起来很轻量级,将调用委托给 ChatService
对象,并且在调用集线器的 OnDisconnected()
时我不再遇到错误。
并且不要忘记在容器中注册您的服务:
container.Register<IChatService, ChatService>(hybrid);
我在 Using Simple Injector with SignalR and my services are successfully resolved, not until OnDisconnected
is called on the Hub class. Then I had to follow this question
我得到异常说:
[SimpleInjector.ActivationException] The registered delegate for type ChatHub threw an exception. The ChatHub is registered as 'Hybrid Web Request / Execution Context Scope' lifestyle, but the instance is requested outside the context of a Hybrid Web Request / Execution Context Scope.
堆栈跟踪:
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstance(Type serviceType)
at QuickChat.Hubs.SimpleInjectorHubActivator.Create(HubDescriptor descriptor) in c:\Users\Peter\Documents\Visual Studio 2013\Projects\QuickChat\QuickChat\Hubs\SimpleInjectorHubActivator.cs:line 21
at Microsoft.AspNet.SignalR.Hubs.DefaultHubManager.ResolveHub(String hubName)
at Microsoft.AspNet.SignalR.Hubs.HubDispatcher.CreateHub(IRequest request, HubDescriptor descriptor, String connectionId, StateChangeTracker tracker, Boolean throwIfFailedToCreate)
InnerException:
at SimpleInjector.Scope.GetScopelessInstance[TService,TImplementation](ScopedRegistration`2 registration)
at SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration`2 registration, Scope scope)
at SimpleInjector.Advanced.Internal.LazyScopedRegistration`2.GetInstance(Scope scope)
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.GetInstance()
查看下面我当前的代码配置。 集线器激活器:
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);
}
}
SimpleInjector 服务注册:
public class SimpleInjectorConfig
{
public static void Register()
{
// Create the container as usual.
var container = new Container();
var hybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new SimpleInjector.Integration.Web.WebRequestLifestyle(),
new ExecutionContextScopeLifestyle());
// Register types:
container.RegisterSingle<MembershipRebootConfiguration>(MembershipRebootConfig.Create);
container.Register<DefaultMembershipRebootDatabase>(() => new CustomMembershipRebootDatabase());
container.Register<UserAccountService>(() => new UserAccountService(container.GetInstance<MembershipRebootConfiguration>(), container.GetInstance<IUserAccountRepository>()));
container.Register<AuthenticationService, SamAuthenticationService>();
container.RegisterPerWebRequest<IUserAccountQuery, DefaultUserAccountRepository>();
container.RegisterPerWebRequest<IUserAccountRepository, DefaultUserAccountRepository>();
container.Register(() => new DataAccess.EF.DataContext(), hybrid);
container.Register<IUnitOfWork, UnitOfWork>(hybrid);
container.Register<IUserService, UserService>(hybrid);
//Register SimpleAuthentication callback provider class
container.RegisterPerWebRequest<IAuthenticationCallbackProvider, SimpleAuthenticationProviderController>();
//Register SimpleAuthentication MVC controller.
container.RegisterPerWebRequest<SimpleAuthenticationController>(
() => new SimpleAuthenticationController(container.GetInstance<IAuthenticationCallbackProvider>(), null));
// This is an extension method from the integration package.
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
// This is an extension method from the integration package as well.
container.RegisterMvcIntegratedFilterProvider();
//Enable injections to SignalR Hubs
var activator = new SimpleInjectorHubActivator(container);
container.Register<ChatHub, ChatHub>(hybrid);
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => activator);
container.Verify();
//Set dependency resolver for MVC
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
}
Global.asax.cs:
protected void Application_Start()
{
SimpleInjectorConfig.Register();
// Register the default hubs route: ~/signalr/hubs
RouteTable.Routes.MapHubs();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}
你的混合生活方式是错误的。你应该改变谓词:
var hybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new ExecutionContextScopeLifestyle(),
new SimpleInjector.Integration.Web.WebRequestLifestyle());
提示:与其在整个组合根中重复使用该 hybrid
变量,还可以将其设置为默认作用域生活方式,如下所示:
container.Options.DefaultScopedLifestyle = hybrid;
通过这种方式,您可以将注册更改为以下内容:
container.Register<ChatHub, ChatHub>(Lifestyle.Scoped);
这使您的注册更容易、更清晰。
正如史蒂文在他的回答中所说,我的混合生活方式是错误的。我不得不改变谓词:
var hybrid = Lifestyle.CreateHybrid(
() => container.GetCurrentExecutionContextScope() != null,
new ExecutionContextScopeLifestyle(),
new SimpleInjector.Integration.Web.WebRequestLifestyle());
在与 Steven GitHub 讨论了几次之后,我得出了一个结论。
我必须将我的 ChatHub
变成 Humble Object 并从中提取所有逻辑并放入一个单独的 class 中,该 class 实现一个服务接口,该接口由公开所有逻辑的方法组成最初包含在 ChatHub
public interface IChatService
{
void OnConnected(Guid userId, string connectionId, HubConnectionContext clients);
void OnDisconnected(Guid userId, string connectionId);
void Broadcast(string message, string username, HubConnectionContext clients);
}
public class ChatService : IChatService
{
private readonly IUnitOfWork _unitOfWork;
public UserChatService(IUnitOfWork unitOfWork) {
_unitOfWork = unitOfWork;
}
public void OnConnected(Guid userId, string connectionId, HubConnectionContext clients) {
//Perform other operation using _unitOfWork
}
public void OnDisconnected(Guid userId, string connectionId) {
//Perform other operation using _unitOfWork
}
public void Broadcast(string message, string username, HubConnectionContext clients) {
//Perform other operation using _unitOfWork and HubConnectionContext
//broadcast message to other connected clients
clients.others.broadcast(message);
}
}
HubConnectionContext
对我来说真的像是运行时数据,所以我决定将它作为参数传递给方法。
有了这个,我的集线器 ChatHub
看起来很轻量级,将调用委托给 ChatService
对象,并且在调用集线器的 OnDisconnected()
时我不再遇到错误。
并且不要忘记在容器中注册您的服务:
container.Register<IChatService, ChatService>(hybrid);