我正在使用Owin,Web API,实体框架,ASP.NET身份创建API。我正在使用Simple Injector作为我选择的DI框架。
在Owin启动过程中,我想用一些示例数据为我的数据库播种。这是由实现IDatabaseInitializer
的类处理的,如下所示:
public class MyDbInitializer : DropCreateDatabaseAlways<MyDataContext>
{
private readonly IUserManager _userManager;
public MyDbInitializer(IUserManager userManager)
{
_userManager = userManager;
}
protected override void Seed(MyDataContext context)
{
SeedIdentities();
}
private void SeedIdentities()
{
var user = new User
{
UserName = "someUsername",
Email = "some@email.com"
};
_userManager.CreateAsync(user, "Password");
}
IUserManager
是ASP.NET Identiy UserManager
类的代理,它间接依赖于IUnitOfWork
。如果你想知道,IUserManager
是这样注册的:
container.Register(typeof(IUserManager),
() => container.GetInstance<IUserManagerFactory>().Create());
因为我想为每个Web API请求使用一个工作单元,所以我已将IUnitOfWork
注册如下:
container.RegisterWebApiRequest<IUnitOfWork, MyUnitOfWork>();
除了解析IUserManager
类中的MyDbInitializer
依赖项之外,这对于所有事情都很好。在应用程序启动期间,SimpleInjector失败并出现以下ActivationException:
SimpleInjector.ActivationException was unhandled by user code
HResult=-2146233088
Message=The registered delegate for type IUserManagerFactory threw an exception. The IUnitOfWork is registered as 'Web API Request' lifestyle, but the instance is requested outside the context of a Web API Request.
Source=SimpleInjector
StackTrace:
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.GetInstance[TService]()
at Project.WebApi.CompositionRoot.SimpleInjectorCompositionRoot.<RegisterSecurityDependencies>b__c() in c:\code\Project\Project.WebApi\CompositionRoot\SimpleInjectorCompositionRoot.cs:line 130
at lambda_method(Closure )
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.GetInstance()
InnerException: SimpleInjector.ActivationException
HResult=-2146233088
Message=The IUnitOfWork is registered as 'Web API Request' lifestyle, but the instance is requested outside the context of a Web API Request.
Source=SimpleInjector
StackTrace:
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()
InnerException:
我猜Owin Startup.cs
类被认为是在Web API请求生命周期之外,并且数据库初始化程序中的构造函数注入失败,因为它由Startup.cs
类调用。
我不确定如何解决这个问题。我应该使用混合生活方式来注册IUnitOfWork
,还是有更好的解决方案?
答案 0 :(得分:25)
你是对的。在启动期间,没有Web API请求。幸运的是,WebApiRequestLifestyle(由RegisterWebApiRequest
扩展方法使用)使用了ExecutionContextLifestyle,因此按照以下方式“模拟”Web请求非常简单:
// using SimpleInjector.Extensions.ExecutionContextScoping;
using (container.BeginExecutionContextScope())
{
var initializer = container.GetInstance<MyDbInitializer>();
intializer.InitializeDatabase();
}
答案 1 :(得分:0)
此外,如果您托管在IIS中,集成管道将为管道的每个阶段创建一个新的CallContext,这是SimpleInjector存储执行上下文的地方。
因此,如果您在管道的不同阶段中的一个中间件中执行BeginExecutionContextScope而不是运行Web API代码,则SimpleInjector执行上下文将不会保留。
您可以使用app.UseStageMarker
来调整中间件在管道中执行的位置,但是我无法让SimpleInjector执行上下文通过我的所有OWIN auth中间件继续存在,然后进入Web API。尽管使用相同的SimpleInejctor容器,但我的DelegatingHandlerProxy中的以下代码始终会创建新的执行范围
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Trigger the creation of the DependencyScope to ensure the instance
// is resolved within that scope.
request.GetDependencyScope();
}