Search code examples
asp.net-mvcasp.net-web-apidependency-injectionunity-container

MVC Web API and Unity for dependency injection


I'm building a very simple set of controllers that I would like to inject dependencies into.

My Web Api project is using .net 4.5.1 (vs2015) and I am using Unity for dependency injection (really really new to Unity).

Here's what I've done:

  1. New Project > ASP.Net web appliction > Web Api Project (no auth)
  2. Tools > Nuget Package Manager > Manage Packages for solution... Search for "Unity.MVC" and install package.
  3. I created the following interface and classes:

    public interface IExample
    {
        void DoWork();
    }
    
    public class ServiceA : IExample
    {
        public void DoWork()
        {
            Console.Write("A");
        }
    }
    
    public class ServiceB : IExample
    {
        public void DoWork()
        {
            Console.Write("B");
        }
    }
    

In my simple controller, I implemented this:

    public class HomeController : Controller
    {
        IExample instance;

        public HomeController(IExample injected)
        {
            instance = injected;
        }

        public ActionResult Index()
        {
            ViewBag.Title = "Home Page";

            return View();
        }
    }

I have these two newly added files from Unity:

enter image description here

I add the following code to the UnityConfig.cs:

    public static void RegisterTypes(IUnityContainer container)
    {
        // NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
        // container.LoadConfiguration();

        // TODO: Register your types here
        //container.RegisterType<IProductRepository, ProductRepository>();

        container.RegisterType<IExample, ServiceA>();
    }

So far - ALL GOOD! I get the DI into the view as expected. Now I want to do the same for my web api controller, like so:

Run - and get this error:

An error occurred when trying to create a controller of type 'ItemController'. Make sure that the controller has a parameterless public constructor.

What have I done wrong? Full exception:

{
   "Message": "An error has occurred.",
   "ExceptionMessage": "An error occurred when trying to create a controller of type 'ItemController'. Make sure that the controller has a parameterless public constructor.",
   "ExceptionType": "System.InvalidOperationException",
   "StackTrace": "   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
   "InnerException":    {
      "Message": "An error has occurred.",
      "ExceptionMessage": "Type 'WebApplication2.Controllers.ItemController' does not have a default constructor",
      "ExceptionType": "System.ArgumentException",
      "StackTrace": "   at System.Linq.Expressions.Expression.New(Type type)\r\n   at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
   }
}

Thanks in advance!


Solution

  • The ControllerActivator cannot instantiate your HomeController because its constructor is not marked as public (hence it's actually private).

    When you are not providing any constructor at all, the compiler automatically creates a public one for you, but since you are providing one (that is not public) you're ending up with no public constructor.

    Try this:

    public HomeController(IExample injected)
    {
        instance = injected;
    }
    

    Update:

    As per your edit, for integrating Unity with API controllers, you'll have to install the Unity.WebAPI package as well.

    More on WebAPI inegration: http://www.asp.net/web-api/overview/advanced/dependency-injection