Larrifax Larrifax - 1 month ago 10
C# Question

Simple Injector fails to inject per Web API request registered class during Owin startup

I'm creating an API using Owin, Web API, Entity Framework, ASP.NET Identity. I'm using Simple Injector as my DI framework of choice.

During the Owin startup process, I want to seed my database with some sample data. This is handled by a class implementing

IDatabaseInitializer
, which looks something like this:

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
is a proxy for the ASP.NET Identiy
UserManager
class, which indirectly depends on
IUnitOfWork
. In case you're wondering,
IUserManager
is registered like this:

container.Register(typeof(IUserManager),
() => container.GetInstance<IUserManagerFactory>().Create());


Because I want to use a single unit of work per Web API request, I have registered my
IUnitOfWork
as following:

container.RegisterWebApiRequest<IUnitOfWork, MyUnitOfWork>();


This is working fine and dandy for everything except when resolving the
IUserManager
dependency in the
MyDbInitializer
class. During application startup, SimpleInjector fails with the following 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:


I guess that the Owin
Startup.cs
class is regarded as being outside the Web API request lifecycle, and that constructor injection in the database initializer fails because it is called by the
Startup.cs
class.

I'm unsure how to solve this problem. Should I use a hybrid lifestyle for the registration of
IUnitOfWork
, or is there any better solution?

Answer Source

You are correct. During the startup, there is no Web API request. Fortunately, the WebApiRequestLifestyle (that is used by the RegisterWebApiRequest extension method) uses the ExecutionContextLifestyle under the covers, so it is really simple to 'simulate' a web request as follows:

// using SimpleInjector.Extensions.ExecutionContextScoping;

using (container.BeginExecutionContextScope())
{
    var initializer = container.GetInstance<MyDbInitializer>();
    intializer.InitializeDatabase();
}