简体   繁体   中英

StructureMap thinks it has to inject to constructor and throws exception

I'm using StructureMap and ASP.Net Identity in my application. When I have this line in my Application_Start

ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());

and this is StructureMapControllerFactory :

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null && requestContext.HttpContext.Request.Url != null)
            throw new InvalidOperationException(string.Format("Page not found: {0}",
                requestContext.HttpContext.Request.Url.AbsoluteUri.ToString(CultureInfo.InvariantCulture)));
        return ObjectFactory.GetInstance(controllerType) as Controller;
    }
}

return ObjectFactory.GetInstance(controllerType) as Controller; throws a StructureMapConfigurationException exception saying:

No default Instance is registered and cannot be automatically determined for type 'IUserStore<Person>'

but if I remove ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory()); line everything goes fine so it's StructureMap's problem not my code.

I think the exception is clear. It's probably about the AccountController from the Identity template, which comes with 2 constructors.

StructureMap will use the most greediest constructor by default. The template comes with 2 constructors, one default constructor and one constructor with an ApplicationUserManager object.

Without StructureMap the default constructor is called and the ApplicationUserManager will be resolved using the service locator anti pattern .

StructureMap now must create the ApplicationUserManager and because this is a concrete type it will try. If it was an abstract it will throw the exception right there. The ApplicationUserManager however has a single constructor which needs an IUserStore<Person> . Because this is an abstract and the container has no registration of this type, StructureMap is unable to create the type for you.

To solve this you should remove the default constructor and Register the ApplicationUserManager and depending services which is at least some component which, implements IUserStore.

Edit: While the solution you mentioned in the comments may work, this is not the preferable solution because of:

  1. Having multiple constructors is an anti-pattern
  2. You are now using the service locator anti pattern for resolving the ApplicationUserManager from the HttpContext

The templates that come with VS2013 need some work to use with dependency injection. This will cost some time. The good news is, it is possible and doable and will greatly improve your knowledge of Owin , Asp.Net Identity , Dependency Injection and SOLID design .

There are several blogs on how to start refactoring the templates to work with dependency injection. You could read about that here and here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM