Account Controller wire-up

Oct 30, 2013 at 12:42 AM
Edited Oct 30, 2013 at 4:06 AM
Hi, I'm having an issue where container.Verify(); throws an exception when the MVC 5 application starts.:

"The configuration is invalid. Creating the instance for type AccountController failed. The registered delegate for type AccountController threw an exception. The registered delegate for type UserManager<ApplicationUser> threw an exception. No registration for type UserManager<ApplicationUser> could be found and an implicit registration could not be made. The constructor of the type UserManager<ApplicationUser> contains the parameter of type IUserStore<ApplicationUser> with name 'store' that is not registered. Please ensure IUserStore<ApplicationUser> is registered in the container, or change the constructor of UserManager<ApplicationUser>."

I used the MVC3 Quick start NuGet package to start.

Out of the box AccountController, I commented out the default constructor:
    [Authorize]
    public class AccountController : Controller
    {
        // public AccountController()
        //    : this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
        // {
        // }

        public AccountController(UserManager<ApplicationUser> userManager)
        {
            UserManager = userManager;
        }
Global.asax:
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            SimpleInjectorInitializer.Initialize();
        }
SimpleInjectorInitializer (with Boostrapper that wires up the Repos):
    public static class SimpleInjectorInitializer
    {
        /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
        public static void Initialize()
        {
            // Did you know the container can diagnose your configuration? Go to: http://bit.ly/YE8OJj.
            var container = new Container();
            
            InitializeContainer(container);

            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
            
            container.RegisterMvcAttributeFilterProvider();
       
            container.Verify();
            
            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
        }
     
        private static void InitializeContainer(Container container)
        {
            RepositoryBoostrapper.Bootstrap(container);

            // For instance:
            // container.Register<IUserRepository, SqlUserRepository>();
        }
    }
Thanks
Coordinator
Oct 30, 2013 at 8:41 AM
The exception states:
The constructor of the type UserManager<ApplicationUser> contains the parameter of type IUserStore<ApplicationUser> with name 'store' that is not registered. Please ensure IUserStore<ApplicationUser> is registered in the container
I'm not sure if I can add something here; you didn't register IUserStore<ApplicationUser>.

AccountController depends on a UserManager<ApplicationUser> and since UserManager<T> is concrete, Simple Injector will try to create it for you (with the transient lifestyle), even though its not registered. But the constructor of UserManager<T> contains an IUserStore<T> abstraction and since this is no concrete type, Simple Injector can't automatically create it for you.

Looking at the code you commented out, the following registration would do the trick:
container.Register<IUserStore<ApplicationUser>>(() =>
    new UserStore<ApplicationUser>(new ApplicationDbContext()));
Or you can register it as open generic type:
container.RegisterOpenGeneric(typeof(IUserStore<>), typeof(UserStore<>));
container.Register<IInterfaceOfApplicationDbContext>(() => new ApplicationDbContext());
Oct 30, 2013 at 3:04 PM
Edited Oct 30, 2013 at 3:31 PM
When I wire this up I get the following exception:

An exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll but was not handled in user code

Additional information: The default DbConfiguration instance was used by the Entity Framework before the 'ContextConfiguration' type was discovered. An instance of 'ContextConfiguration' must be set at application start before using any Entity Framework features or must be registered in the application's config file. See http://go.microsoft.com/fwlink/?LinkId=260883 for more information.

I have two DbContext classes both pointing to the same DB using EF6. One for Security ApplicationDbContext, and the other just handles regular back office types ClientManagementContext. They are in two different class libraries. In the library with ClientMangementContext, I have a ContextConfiguration class that handles my SqlAzureExecutionStrategy (retry logic).

When I new up my ApplicationDbContext from a bootstrapper class in my MVC application (your code example), am I somehow telling EF to use the default DbConfiguration instead of the ContextConfiguration?

I don't have a ContextConfiguration in the class library where my ApplicationDbContext lives, so when S.I. gets to newing up ClientManagmentContext (where ContextConfiguration lives), SI has already build the Default Configuration because of the newing up of ApplicationDbContext?

To test, when I removed my ContextConfiguration from my ClientManagmentContext class library, then at least the application starts and the exception was not thrown. I'll need to test to see the two contexts actually work as they had before. Also, by taking out the ContextConfiguration, I no longer have a Azure DB retry strategy.

Also, before I added the ApplicationDbContext, the ClientManagmentContext with ContextConfiguration and S.I. seemed to work (no exceptions thrown and I was able to query/write at will to the db). But I had not fully tested the Azure retry logic.

I'll add to this post when I'm sure the two contexts work.

I can supply code if you like.

Thanks.
Coordinator
Oct 30, 2013 at 4:00 PM
The problem seems not Simple Injector related and I'm not sure how you would solve this. I think the question is, how would you do this without Dependency Injection? If you need some configuration class that's not available in the Composition Root, you can define a factory class in the DbContext's project and register a delegate in Simple Injector that calls that factory class.
Oct 30, 2013 at 5:25 PM
Is there a way to see what is "newed" up and in what order (a tool or view in MS VS) by S.I. or in general so I can see where/when I need to new up the DbConfiguration instance?

Thanks.
Coordinator
Oct 30, 2013 at 5:41 PM
The beta1 of version 2.4 contains an Container.InstanceCreated event (warning: it will be renamed to RegisterInitializer in beta2) that allows you to get notified about creation of types (see this work item). With the current 2.3, you can use container.RegisterInitializer<[TypeToCheck]>(instance => { action })
Marked as answer by dot_NET_Junkie on 2/26/2014 at 1:23 PM
Oct 31, 2013 at 2:12 PM
Thanks for this!