的DbContext创建到消息处理器
问题描述:
我有一个DLL至极露出型等的DbContext创建到消息处理器
public class MyDbContext {
[...]
}
这个库里面我也有一个IPackage
实现这在容器注册MyDbContext
等
public void RegisterServices(Container container) {
container.Register<MyDbContext>(Lifestyle.Scoped);
}
该组件然后引用两种不同类型的应用程序: - 一个web api项目 - 一个asp.net mvc应用程序
这是web API项目
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
InitializeContainer(container);
container.RegisterWebApiControllers(GlobalConfiguration.Configuration);
container.Verify();
的初始化,这是MVC应用
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
的初始化当我接收来自Rebus的队列的消息(在MVC应用程序)的容器尝试instatiate这样
public class MyHandler : BaseMessageHandler, IHandleMessages<MyMessage>, IHandleMessages<IFailed<MyMessage>>
{
public MyHandler(ILog logger, MyDbContext context) {
_logger = logger;
_context = context;
}
}
消息处理程序,但我收到一个错误说
Rebus.Retry.ErrorTracking.InMemErrorTracker - 未处理的异常1,同时处理消息ID 85feff07-01a6-4195-8deb-7c8f1b62ecc3:SimpleInjector.ActivationException:该MyDbContext被注册为“网络请求的生活方式,但实例在活动(Web请求)范围的上下文之外请求。
与以下堆栈跟踪
at SimpleInjector.Scope.GetScopelessInstance[TImplementation](ScopedRegistration`1 registration)
at SimpleInjector.Scope.GetInstance[TImplementation](ScopedRegistration`1 registration, Scope scope)
at SimpleInjector.Advanced.Internal.LazyScopedRegistration`1.GetInstance(Scope scope)
at lambda_method(Closure)
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstance[TService]()
我还试图以设置异步作用域服饰在MVC应用程序,但该错误基本上是相同的。
答
Rebus在后台线程上运行您的处理程序,而不是在Web请求线程上运行。这意味着不可能使用WebRequestLifestyle
作为Rebus管道的一部分。
您应该确保在执行处理程序之前明确启动了异步作用域。你可以用装饰器/代理来做到这一点。
最重要的是,您应该为您的MVC应用程序使用混合生活方式,因为MVC使用WebRequestLifestyle
而不是`AsyncScopedLifestyle。
你可以在你的MVC应用程序中应用的混合动力生活方式如下:
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
defaultLifestyle: new AsyncScopedLifestyle(),
fallbackLifestyle: new WebRequestLifestyle());
你的装饰应如下所示:
public sealed class AsyncScopedMessageHandler<T> : IHandleMessages<T>
{
private readonly Container container;
private readonly Func<IHandleMessages<T>> decorateeFactory;
public AsyncScopedMessageHandler(Container container, Func<IHandleMessages<T>> factory)
{
this.container = container;
this.decorateeFactory = factory;
}
public async Task Handle(T message) {
using (AsyncScopedLifestyle.BeginScope(this.container)) {
var decoratee = this.decorateeFactory.Invoke();
await decoratee.Handle(message);
}
}
}
如下您可以注册你的装饰:
container.RegisterDecorator(
typeof(IHandleMessages<>),
typeof(AsyncScopedMessageHandler<>),
Lifestyle.Singleton);
你应该在MVC和你的Web API项目中注册这个装饰器吨。
嗨史蒂文,感谢您的及时答复。您能否澄清我需要对我的MessageHandler进行哪些修改?其实我只是注册我的处理程序为'container.Register,MyMessageHandler>(Lifestyle.Transient)'。我应该改变它吗? –
Lorenzo
嗨@Lorenzo,你不必改变任何东西到你的消息处理程序或你的注册;这就是Simple Injector的美妙结合了Rebus提供的精心设计的抽象。你只需将你的装饰器注册为最后的装饰器(如果你有更多的),它就应该开始工作。 – Steven
伟大的质量答案。谢谢! – Lorenzo