4

I am trying to setup IoC using StructureMap for my ASP.NET MVC 4 site. Here is my StructureMapDependencyResolver class:

    public class StructrueMapDependencyResolver : IDependencyResolver
    {        
        public object GetService(Type serviceType)
        {
            return IocContainer.GetInstance(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return IocContainer.GetAllInstances(serviceType);
        }
    }

Here is part of my IocContainer

public static class IocContainer
{
    ....

    public static object GetInstance(Type t)
    {
        return ObjectFactory.TryGetInstance(t);
    }

    public static IEnumerable<object> GetAllInstances(Type t)
    {
        return ObjectFactory.GetAllInstances(t).Cast<object>();
    }
}

Here is what my Global.aspx.cs looks like

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);

            IocContainer.RegisterAllTypes(Server.MapPath("~\\Bin"), AssemblyList.MyAssemblies);
            DependencyResolver.SetResolver(new StructrueMapDependencyResolver());
        }
    } 

Finally I have a simple controller that depends on a service:

  public class ManagePostController: Controller
  {
      private ISomeService _someService;

      public ManagePostController(ISomeService svc)
      {
          _someService= svc;
      }
  }

When I start my website, got the following exception:

No parameterless constructor defined for this object.

[InvalidOperationException: An error occurred when trying to create a controller of type 'Foothill.WebAdmin.Controllers.ManagePostController'. Make sure that the controller has a parameterless public constructor.] System.Web.Mvc.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType) +247

I am not sure where I need to change?

2
  • Isn't DependencyResolver for WebApi only? Commented Aug 11, 2013 at 17:36
  • No @WiktorZychla I dont think that's the case. The MSDN page for IDependencyResolver doesn't mention anything about being WebApi only. Commented Aug 11, 2013 at 18:00

2 Answers 2

4

Replace your IocContainer.GetInstance(Type) implementation with the following:

public static object GetInstance(Type t)
{
    return t.IsAbstract || t.IsInterface
                    ? ObjectFactory.TryGetInstance(t)
                    : ObjectFactory.GetInstance(t);
}

The ASP.NET MVC extensibility model will attempt to resolve various components (e.g. IControllerActivator) which are optional (if you return null, MVC will use the default components instead). That's why we have the ObjectFactory.TryGetInstance call - this will only resolve a component if you explicitly configure it within the container.

For resolving controllers (which are concrete types) ObjectFactory.GetInstance should be used - this creates an instance even though the controller type was never explicitly configured.

The code snippet above is what I use in my projects and I just realized it's very similar to what is present in the StructureMap MVC4 Nuget package (see line 123 in this file).

By the way, I think you could simply use the NuGet package instead of going through these steps yourself.


Update

Regarding IControllerActivator: that's just another extensibility point. If no controller activator is registered, the dependency resolver is used instead:

If there is no IControllerActivator present in the dependency resolver, we will then ask the dependency resolver to create the concrete controller type by calling GetService(controllerType). (quote from Brad Wilson's blog)

Also, an explanation of why there are both IDependencyResolver and IControllerActivator: http://forums.asp.net/post/4241343.aspx

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks @w0lf, it works now. But I still have the following question: Since I want to use the default controller activator, so I didn't register any concrete controller activator type in SM. Therefore ObjectFactory.TryGetInstance(t) will return null for a t == controller activator. And this will make the MVC4 to fall over to the default activator. Am I right?
The contract of the IDependencyResolver's GetService method states that "Implementers should return Nothing when the service cannot be found.". In other words, the implementation should always call TryGetInstance; not conditionally.
@Steven that works if all the Controllers in the application are manually configured in the container. StructureMap, however, offers this feature that it can (attempt to) resolve concrete types even though they are not explicitly configured.
Other containers (Castle, Ninject, Simple Injector) have this same behavior, but I'm not sure why that's relevant. If the container can resolve that instance (whether or not it is registered directly or not), it should resolve that instance (unless of course TryGetInstance does not resolve unregistered concrete types). But even if the container can resolve unregistered concrete types, it is still very advisable to register all your controllers explicitly to prevent this problem
@Steven Exactly: in StructureMap TryGetInstance will return null for a non-registered concrete type, whereas GetInstance will perform the resolution. Thanks for pointing out the WebAPI problem; I haven't been aware of that.
|
0

I had the same problem using IoC container and googled for hours about it but could not get rid of it.finally I install last update of Visual Studio(VS Version 2013 and update3 in my case) and the probelm get solved.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.