21

I'm very new to using Unity, but my problem is that whenever I call my web service, I get an exception stating that

"Make sure that the controller has a parameterless public constructor"

I've followed multiple tutorials and I still get the same issue.

In the Register function of my WebApiConfig class, I have

var container = new UnityContainer();
container.RegisterType<IValidator, Validator>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);

Here is my UnityResolver class

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

public class UnityResolver : IDependencyResolver
{
    protected IUnityContainer container;

    public UnityResolver(IUnityContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        this.container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        container.Dispose();
    }
}

I have not registered any controllers, as every tutorial claims that I don't need to do this. Here is my actual controller

public class Controller: ApiController
{
    private IValidator _validator;

    public Controller(IValidator validator)
    {
        this._validator = validator;
    }

    [HttpPost]
    public void ReceiveIPN()
    {

    }
}

Does anyone have any ideas as to what I can be doing wrong? Thanks!

EDIT 1: Here is the "implementation" of the Validator class. It's pretty empty, because I didn't want to introduce a bug here until I resolved the Unity issue.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;


public class Validator: IValidator
{
    public bool ValidateIPN(string body)
    {
        throw new NotImplementedException();
    }
}

EDIT 2: Here is the entire error response I get when I attempt to call the web api route using Fiddler

{"message":"An error has occurred.","exceptionMessage":"An error occurred when trying to create a controller of type 'Controller'. 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) at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()","innerException":{"message":"An error has occurred.","exceptionMessage":"Type 'Project.Controller' does not have a default constructor","exceptionType":"System.ArgumentException","stackTrace":" at System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"}}

haim770
  • 48,394
  • 7
  • 105
  • 133
Carlos Rodriguez
  • 2,190
  • 2
  • 18
  • 29
  • You have to register your controller with Unity which I don't see you doing. If you're doing that, or if that still doesn't work, total guess, but try naming your controller something other than controller. Sometimes reflection on a class name that shares the same name as something in the framework has weird side effects. – moarboilerplate Apr 13 '15 at 17:13
  • 2
    @moarboilerplate: controllers don't have to be registered. \@Kith: can you show how your Validator looks like? Does it also take in a dependency? – Jeroen Vannevel Apr 13 '15 at 17:14
  • 1
    I'm not registering the controller, and the controller isn't actually named Controller. I changed the name before posting here. @JeroenVannevel I can post the Validator, but it's actually empty lol. I didn't define a constructor explicitly on it, and it only has one method that throws a not implemented exception. I pretty much stopped at this point – Carlos Rodriguez Apr 13 '15 at 17:16
  • Does it work when you remove the dependency in your controller's constructor? – Jeroen Vannevel Apr 13 '15 at 17:17
  • @JeroenVannevel Yes it does – Carlos Rodriguez Apr 13 '15 at 17:18
  • Then the problem must be located in the validator. Can you post the implementation of Validator? – Jeroen Vannevel Apr 13 '15 at 17:22
  • @JeroenVannevel Ah right. – moarboilerplate Apr 13 '15 at 17:22
  • @JeroenVannevel I've added the validator "implementation". It's pretty empty though. Thanks for taking the time – Carlos Rodriguez Apr 13 '15 at 17:25
  • I've looked at most things I can think of that typically cause this. Can you share the exact stacktrace? Maybe that contains any clues. – Jeroen Vannevel Apr 13 '15 at 17:33
  • @JeroenVannevel I've updated the question with the trace. – Carlos Rodriguez Apr 13 '15 at 17:37
  • The error seems to be clear. Make sure your controller class has a default (parameterless) constructor. Try that and see what happens. – kha Apr 13 '15 at 17:37
  • 1
    @kha Although that does work, it doesn't solve my problem. If I add a parameterless constructor, that's the constructor that ends up being used, and my Validator dependency isn't injected into my Controller. The whole point of my using Unity is to be able to inject my dependencies in, for unit testing purposes. – Carlos Rodriguez Apr 13 '15 at 17:39
  • @Kith: according to [this answer](http://stackoverflow.com/a/15910758/1864167) you can get a more detailed exception message if you explicitly register your controllers. If that doesn't yield anything though, throw your solution in a zip file and upload it somewhere so I can take a look around locally (or put it on github). – Jeroen Vannevel Apr 13 '15 at 17:45
  • Sorry I completely misread your question and you're completely right. My bad. Based on this sample http://www.codeproject.com/Articles/797132/Dependency-Injection-in-MVC-Using-Unity-IoC-Contai you may need to do this in a custom `DefaultControllerFactory` but I can't say for sure. Again, my apologies for not understanding the question properly. – kha Apr 13 '15 at 17:50
  • Did you make sure your `WebApiConfig.Register` method is invoked? – haim770 Apr 13 '15 at 17:57
  • @JeroenVannevel It doesn't look like explicitly registering my controller changed the exception message. Also, I really can't share the entire project for legal reasons, as much as I'd love to (to get this figured out lol). Sorry about that, and I appreciate all the help you've given me so far. – Carlos Rodriguez Apr 13 '15 at 17:58
  • @kha No worries :-). I looked into the DefaultControllerFactory, but it looks like that's not the ideal approach (at least, any more). If I can't figure out the DependencyResolver approach, I'll definitely look into that. – Carlos Rodriguez Apr 13 '15 at 17:58
  • @haim770 Yes I did. I put a break-point there, and it's always reached when i first start up the project and call the web service. – Carlos Rodriguez Apr 13 '15 at 17:58
  • Perhaps a shot in the dark, but try to change your controller name from `Controller` to something like `MyController`. – haim770 Apr 13 '15 at 17:59
  • @Kith: I suggest you create a minimal example that reproduces the problem. If you can do that then you can share it with us -- if you can't do that then you can gradually build up your project and you'll notice eventually where things break down. – Jeroen Vannevel Apr 13 '15 at 18:01
  • @haim770 I've changed the name of that controller many times and it doesn't seem to be the issue. Thanks though :-) – Carlos Rodriguez Apr 13 '15 at 18:06
  • @JeroenVannevel Will do. I'll post back as soon as I have any other clues. Thanks again. – Carlos Rodriguez Apr 13 '15 at 18:06
  • @Kith, Could it be that `RegisterType` is actually referring to `System.Web.WebPages.IValidator`? Or `Validator` is actually referring to `System.Web.WebPages.Validator`? Or both? – haim770 Apr 13 '15 at 18:15
  • @Tom, that's not passing it to the ctor, it merely sets the lifetime. – haim770 Apr 13 '15 at 18:17
  • Dumb question, but are you making sure you're calling your `WebApiConfig.Register` method from Global.asax? – moarboilerplate Apr 13 '15 at 18:25
  • @JeroenVannevel I managed to figure out what was going on and posted the solution as an answer. Thanks for the help – Carlos Rodriguez Apr 13 '15 at 20:20

4 Answers4

26

So, after hours of banging my head against a wall, I've found that this wasn't working because I had an OWIN/Katana Startup.cs class in my project. Now I don't know exactly what's going on here, so any more information would be great.

Basically, since I was using OWIN/Katana, I had a Startup.cs file that created a new HttpConfiguration object and configured it, similar to how it's done in the WebApiConfig.cs class.

private void ConfigureWebApi(HttpConfiguration config)
{
    config.MapHttpAttributeRoutes();
    var container = new UnityContainer();
    container.RegisterType<IValidator, Validator>();
    config.DependencyResolver = new UnityDependencyResolver(container);

    var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter().First();
    jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}

It looks like the code first runs through the WebApiConfig's Register function, and THEN overrides that HttpConfiguration object with the one generated in the Startup.cs file. I had to move my container setup stuff here in order for it to work.

Sorry that I didn't bring up the OWIN stuff before. This is fairly new to me and I didn't realize it was relevant. Hopefully this saves someone else the pain that I've just been through.

Carlos Rodriguez
  • 2,190
  • 2
  • 18
  • 29
  • 3
    Important detail indeed ;) Glad you were able to solve it though. When using Owin the order of operations is pretty important for some aspects (things like WebApiConfig.Register() and app.UseWebApi() have to be in that order and at the end of the StartUp class). – Jeroen Vannevel Apr 13 '15 at 20:25
  • Hi, I ran into the same problem, solution was to simply pass the config object to the Unity registration function and use the DependencyResolver from that instance: `public static void Register(HttpConfiguration config) { var container = new UnityContainer(); // replace... /* GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); */ // with this: config.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); }` – spilote Nov 17 '16 at 21:51
  • After wasting a lot of time on this, i found answer here. https://forums.asp.net/t/1982840.aspx?Web+API+2+1+Dependency+Injection – Majid Dec 16 '16 at 14:38
  • 1
    if your project is WebApi + Standard views, then just install packages "unity.mvc5" and "unity.webapi". Then in UnityConfig.RegisterComponents type this: `System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); System.Web.Mvc.DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));` – Vladislav Jun 07 '17 at 10:17
1

Your Unity container is probably getting disposed because it's only defined in the scope of your WebApiConfig.Register() method. If you define your container as a member of Global, which will keep your container around for the lifetime of the app, it should work.

Edit: also don't forget to dispose the container on Application_End.

moarboilerplate
  • 1,633
  • 9
  • 23
  • I'm certain this issue is due to scoping, but I'm not sure if the issue is due to the container falling out of scope due to the method scope, or if it's because the container isn't a static property accessible by all threads. – moarboilerplate Apr 13 '15 at 19:04
1
  • Install Unity.mvc5 and Unity.WebApi in a project through nuget package
  • Specify fullnamespace as per below line

Example:

public static class UnityConfig
{
    public static void RegisterComponents()
    {
        var container = new UnityContainer();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();

        DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
    }
}
Alex Riabov
  • 8,655
  • 5
  • 47
  • 48
-1

I know this is an old post but since I just ran into the same problem, the solution was to simply pass the config object to the Unity registration function and use the DependencyResolver from that instance:

EDIT: Just noted that the accepted answer does exacly this... Sorry for the spam ;-)

public static class UnityConfig
{
    public static void Register(HttpConfiguration config)
    {
        var container = new UnityContainer();

        // register your services here...

        // replace...
        /* GlobalConfiguration.Configuration.DependencyResolver = new      Unity.WebApi.UnityDependencyResolver(container); */

        // with this:
        config.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
    }
}
spilote
  • 89
  • 5