Recently I’ve been trying to get an MVC controller working with the StructureMap.MVC4 NuGet package. In the process, I got a rather uninformative error which had me stumped for a while.
Setting up my controller, I added my interface to the constructor as follows:
public LearningController(IInductionUnitOfWork inductionUnitOfWork) { _inductionUnitOfWork = inductionUnitOfWork; }
After doing this and setting up some other framework related stuff, I tested out my view. Navigating to the view resulted in the extremely useful error “No parameterless constructor defined for this object.“:
Server Error in '/' Application. No parameterless constructor defined for this object. 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.MissingMethodException: No parameterless constructor defined for this object. Source Error: An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below. Stack Trace: [MissingMethodException: No parameterless constructor defined for this object.] System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0 System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +971 System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark) +1067 System.Activator.CreateInstance(Type type, Boolean nonPublic) +574 System.Activator.CreateInstance(Type type) +464 System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +355 [InvalidOperationException: An error occurred when trying to create a controller of type 'SSW.Induction.WebUI.Controllers.LearningController'. Make sure that the controller has a parameterless public constructor.] System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +493 System.Web.Mvc.DefaultControllerFactory.GetControllerInstance(RequestContext requestContext, Type controllerType) +702 System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName) +472 System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory) +657 System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state) +427 System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContext httpContext, AsyncCallback callback, Object state) +359 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) +324 System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +1059 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +631
After much head scratching, I decided to resolve the dependency in a parameter-less constructor instead of letting the framework take care of it. My reasoning behind this was in the hope that this would expose the underlying error during dependency resolution. I added a parameter-less constructor as the error suggested, and called the StructureMap ObjectFactory
from there, to resolve the dependency for my interface:
public LearningController() { IInductionUnitOfWork l = StructureMap.ObjectFactory.GetInstance(); }
It worked! By calling GetInstance in this manner, the actual exception surfaces as follows:
Server Error in '/' Application. StructureMap Exception Code: 202 No Default Instance defined for PluginFamily SSW.Induction.DataAccess.IDbContext, SSW.Induction.DataAccess, Version=0.11.5049.39157, Culture=neutral, PublicKeyToken=null 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: StructureMap.StructureMapException: StructureMap Exception Code: 202 No Default Instance defined for PluginFamily SSW.Induction.DataAccess.IDbContext, SSW.Induction.DataAccess, Version=0.11.5049.39157, Culture=neutral, PublicKeyToken=null Source Error: Line 15: public LearningController() Line 16: { Line 17: IInductionUnitOfWork l = StructureMap.ObjectFactory.GetInstance(); Line 18: var x = l.LearningItems.GetAll(); Line 19: }
It turns out that I forgot to set up the IDbContext
map correctly. The new error tells me this straight away, making the problem quite easy to resolve. After setting up the mapping for IDbContext
, the view works straight away.
namespace MyProject.DataAccess.Properties { public class AssemblyRegistry : Registry { public AssemblyRegistry() { For().Singleton().Use().Ctor("connectionString").Is(GetConnectionString()); } } }
In this example, the GetConnectionString()
method gets the connection string from configuration. The Singleton()
method ensures that only one instance of InductionContext
is created.
Is this problem one that you’ve come across before? Do you have a different way of troubleshooting this type of issue? Please leave a comment and let me know.
Thanks Daniel, this idea saved my day. I was struggling figuring out, where I’m missed the mapping in a class with several injected object by StructureMap. By initializing them directly it was easy to point to the wrong class and fix it. Thanks.
Csaba
To anyone wondering why this technique can be so successful, MVC is going to execute any configure controller activator first. If the activator throws an unhandled exception it will fall back to the default activator which attempts to call new THEController() and that returns the “No parameterless constructor defined for this object.”