I've been following this article to try and get ASP.NET Identity working with Simple Injector, but I've been running into some issues. https://github.com/simpleinjector/SimpleInjector/issues/597
I setup my SimpleInjectorInitializer
class to look like this:
public class SimpleInjectorInitializer
{
public static Container Initialize(IAppBuilder app)
{
var container = GetInitializeContainer(app);
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
return container;
}
private static Container GetInitializeContainer(IAppBuilder app)
{
var container = new Container();
//container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.RegisterInstance(app);
container.Register<ApplicationUserManager>();
container.Register(() => new ApplicationDbContext("Your constring goes here"), Lifestyle.Scoped);
container.Register<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>(container.GetInstance<ApplicationDbContext>()), Lifestyle.Scoped);
container.RegisterInitializer<ApplicationUserManager>(manager => InitializeUserManager(manager, app));
container.Register<SignInManager<ApplicationUser, string>, ApplicationSignInManager>(Lifestyle.Scoped);
container.Register(() => container.IsVerifying ? new OwinContext(new Dictionary<string, object>()).Authentication : HttpContext.Current.GetOwinContext().Authentication, Lifestyle.Scoped);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
return container;
}
private static void InitializeUserManager(ApplicationUserManager manager, IAppBuilder app)
{
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
//Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator()
{
RequiredLength = 8,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Configure user lockout defaults
manager.UserLockoutEnabledByDefault = true;
manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
manager.MaxFailedAccessAttemptsBeforeLockout = 3;
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug it in here.
manager.RegisterTwoFactorProvider("Phone Code", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is {0}"
});
manager.RegisterTwoFactorProvider("Email Code", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = app.GetDataProtectionProvider();
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
}
}
When I run my app I get the error To be able to use the Lifestyle.Scoped property, please ensure that the container is configured with a default scoped lifestyle by setting the Container.Options.DefaultScopedLifestyle property with the required scoped lifestyle for your type of application.
.
To fix this, I tried adding container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
If I have that line though I get the error:
The configuration is invalid. The following diagnostic warnings were reported:
-[Lifestyle Mismatch] ApplicationSignInManager (Web Request) depends on ApplicationUserManager (Transient).
-[Short Circuited Dependency] AccountController might incorrectly depend on unregistered type ApplicationSignInManager (Transient) instead of SignInManager<ApplicationUser, String> (Web Request).
-[Short Circuited Dependency] ManageController might incorrectly depend on unregistered type ApplicationSignInManager (Transient) instead of SignInManager<ApplicationUser, String> (Web Request).
-[Disposable Transient Component] ApplicationUserManager is registered as transient, but implements IDisposable.
-[Disposable Transient Component] ApplicationSignInManager is registered as transient, but implements IDisposable.
-[Ambiguous Lifestyles] The registration for SignInManager<ApplicationUser, String> (Web Request) maps to the same implementation (ApplicationSignInManager) as the registration for ApplicationSignInManager (Transient) does, but the registration maps to a different lifestyle. This will cause each registration to resolve to a different instance.
-[Ambiguous Lifestyles] The registration for ApplicationSignInManager (Transient) maps to the same implementation (ApplicationSignInManager) as the registration for SignInManager<ApplicationUser, String> (Web Request) does, but the registration maps to a different lifestyle. This will cause each registration to resolve to a different instance.
I'm at a loss of what to do next, any suggestions would be appreciated.
The amount of error information given by Simple Injector can be a bit overwhelming, but you can distill the information down to two separate problems:
ApplicationUserManager
is registered as TransientApplicationSignInManager
(Transient) instead of SignInManager<ApplicationUser, String>
(Web Request).You should certainly read the Diagnostic Services documentation page in the Simple Injector documentation and especially read about Lifestyle Mismatches, Disposable Transient Components and Short-Circuited Dependencies to understand what Simple Injector is warning about and how to fix the problem.
In short, the fix is two-fold:
ApplicationUserManager
from Transient
to Scoped
to prevent it from having a too-short lifetime and to ensure it is disposed of. Also read this part of the documentation to learn the difference between Transient and Scoped from the context of Simple Injector.AccountController
and ManageController
) don't depend on ApplicationSignInManager
(in their constructor), but instead depend on its base type SignInManager<ApplicationUser, String>
.