Search code examples
c#asp.net-mvcsimple-injector

Simple Injector - Value cannot be null. Parameter name: userManager


I'm trying to get ASP.NET Identity setup with Simple Injector and I'm having problem after problem. I think I'm getting close, but now I'm getting an error saying

Value cannot be null.

Parameter name: userManager

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentNullException: Value cannot be null. Parameter name: userManager

[ArgumentNullException: Value cannot be null. Parameter name: userManager] Microsoft.AspNet.Identity.Owin.SignInManager2..ctor(UserManager2 userManager, IAuthenticationManager authenticationManager) +81 ILETSB.MCLETC.UI.ApplicationSignInManager..ctor(ApplicationUserManager userManager, IAuthenticationManager authenticationManager) in MCLETC.UI\App_Start\IdentityConfig.cs:42 MCLETC.UI.ApplicationSignInManager.Create(IdentityFactoryOptions1 options, IOwinContext context) in MCLETC.UI\App_Start\IdentityConfig.cs:53 Microsoft.AspNet.Identity.Owin.IdentityFactoryProvider1.Create(IdentityFactoryOptions`1 options, IOwinContext context) +14 Microsoft.AspNet.Identity.Owin.d__5.MoveNext() +89 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__7.MoveNext() +179 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +102 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +64 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.d__12.MoveNext() +180 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) +69 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) +64 System.Web.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +389 System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep step) +50 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +163

I'm getting the error message here:

public class ApplicationSignInManager : SignInManager<ApplicationUser, string>
{
    public ApplicationSignInManager(ApplicationUserManager userManager, IAuthenticationManager authenticationManager)
        : base(userManager, authenticationManager)
    {
    }

    public override Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
    {
        return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
    }

    public static ApplicationSignInManager Create(IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
    {
        return new ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
    }
}

Startup class:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app, Container container)
    {
        app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
        app.CreatePerOwinContext(() => container.GetInstance<ApplicationUserManager>());

        // Nothing modified below (template code)
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
            }
        });            
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
        app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
    }
}

SimpleInjectorInitializer:

public class SimpleInjectorInitializer
{
    /// <summary>Initialize the container and register it as MVC5 Dependency Resolver.</summary>
    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();

        // IoC for ASP.NET Identity
        container.RegisterInstance(app);

        container.Register<ApplicationUserManager>(Lifestyle.Scoped);
        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);

        // Register all controllers
        container.RegisterMvcControllers(Assembly.GetExecutingAssembly());

        //Register Modules
        BusinessModule.RegisterServices(container);
        WebModule.RegisterServices(container);

        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"));
        }
    }
}   

Both AccountController and ManageController are setup similar to this:

    private SignInManager<ApplicationUser, string> _signInManager;
    private ApplicationUserManager _userManager;

    public AccountController(ApplicationUserManager userManager, SignInManager<ApplicationUser, string> signInManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
    } 

Am I registering something wrong for the ApplicationUserManager?


Solution

  • If you analyze the stack trace, the problem should become clear:

    • The constructor of Microsoft.AspNet.Identity.Owin.SignInManager<TUser, TKey> is passed a null value for the userManager constructor parameter.
    • The Microsoft.AspNet.Identity.Owin.SignInManager<TUser, TKey> constructor is called from the constructor of your application's ILETSB.MCLETC.UI.ApplicationSignInManager by passing the userManager parameter through.
    • Thew ILETSB.MCLETC.UI.ApplicationSignInManager's constructor is invoked from within the ApplicationSignInManager's own Create method.

    In other words, the static ApplicationSignInManager.Create method is supplying the ApplicationSignInManager constructor with a null value.

    This is how far the analysis can go, because you haven't provided the details of the Create method.

    Try debugging the Create method by placing break points to analyze what's going on and why the value is null.