StructureMap is the leading Dependency Injection/Inversion of Control (IoC) library for .Net development. So of course as I started a brand new project it was one of the very first NuGet packages I installed.
Just as an FYI… if you’re doing ASP.NET MVC development, you’ll want to install the newer StructureMap.MVC5 package, and if you’re adding Web API functionality to your project, you’ll want to use StructureMap.WebApi2 – which will install StructureMap.MVC5 as a dependency.
I had created a Web Application with authentication using the ‘Individual User Accounts’ option enabled. I ran the app prior to installing StructureMap just to make sure it compiled and all was good:
I then clicked around the pages, checking everything was ok. It all worked fine. I then right clicked my solution node in the solution explorer and selected ‘Manage NuGet Packages for Solution…’
On the left side of the Package Manager dialog click and select to view ‘Online’ packages. In the upper right corner type into the search box ‘StructureMap.MVC5’ and hit enter to start searching. You should see StructureMap.MVC5 come up in the search results in the middle column.
Now click the ‘Install’ button and you will see the dialog prompting which projects in the solution to install the package. Select the ones you want and then click the ‘OK’ button.
You will see a progress window appear as NuGet installs the package and a new green tick will appear next to the StructureMap.MVC5 item in the search results.
Now recompile and run the webapp again. This time click on the ‘Register’ link and see what happens.
You will see an unusual error message displayed in Visual Studio:
An exception of type ‘Microsoft.Practices.ServiceLocation.ActivationException’ occurred in Microsoft.Practices.ServiceLocation.dll but was not handled in user code
Click the link that says ‘Copy exception detail to the clipboard’ and then paste it into your favourte text editor. This will give us a hint as to what is going wrong.
You can see that the error occurred while trying to instantiate the AccountController class. This is the controller that manages all the account creation, registration and login activities. Line 11 gives us some more information that points to the root cause.
No default Instance is registered and cannot be automatically determined for type ‘IUserStore<ApplicationUser>’
This is because StructureMap doesn’t know which concrete class to instantiate when it sees an Interface of type IUserStore<ApplicationUser>. If you’re like me (but you’re probably not – you’re a whole lot smarter) you’ll think, that’s fine, I’ll just add a mapping entry to the DefaultRegistry.cs file:
But when you actually try to think what concrete implementation class to provide, you’ll be left scratching your head!
The key to remember here, is that StructureMap is ‘greedy’ about which constructor it will try to call, as it creates concrete instances of each interface. So it’s trying to create an instance of the AccountController class that requires 2 parameters.
Unless we tell it to use a difference constructor, or we figure out all the concrete classes to register in the StructureMap registry. For more information on this checkout this Stackoverflow post on the topic.
The easiest way to solve this error, is to tell StructureMap which constructor to use. In other words, we want to satisfy the error message which asks for a default constructor. Thankfully there is a nice and simple way to do this. Simply add the [DefaultConstructor] attribute to the default, no arg constructor in AccountController.
StructureMap will see this ‘hint’ and use this constructor and all will be fine. You can click the Register or Login links without any exceptions being thrown.
Now, if you don’t like the feel of skipping out on the principle of IoC with the ASP.NET Identity classes, you can register the various concrete classes that are required to let StructureMap invoke it’s preferred constructor – the one with 2 parameters!
We need to register 3 concrete implementations in our registry. I must confess, I got 2/3rds of the way there, but I couldn’t manage to figure out how to register the Owin Authentication Context. Credit for this solution goes to Pouya Yousefi who answered this StackOverflow question. He links to a nice code example on Github too.
Hopefully this helps anyone else who is struggling with their StructureMap config in an ASP.NET MVC web app.