5

Problem

I'm using Unity as IoC and that worked fine, but as I keep adding functionality, it becomes increasingly difficult to pinpoint any errors, because Unity provides an error that is the symptom of the error, not the actual error:

"Message":"An error has occurred.","ExceptionMessage":"An error occurred
when trying to create a controller of type 'MyController'. Make sure that the
controller has a parameterless public
constructor.","ExceptionType":"System.InvalidOperationException"

Background

I have an MVC Web Api controller that has a dependency on a Manager instance (from domain):

public class MyController : ApiController
{
    private IMyManager MyManager { get; set; }

    public MyController(IMyManager myManager)
    {
        this.MyManager = myManager;
    }

    ...
}

The above error occurs because IoC mapping of the IMyManager fails. As it fails, I have no parameter, meaning that MyController is called using a parameterless constructor, but since it doesn't exist (and shouldn't) I get the above error.

What I have tried

So, the error I get is not the 'real' error. The obvious thing is to make sure that every new implementation is registered under IoC, I checked and they are. I do it manually to keep things manageable (oh the irony!).

I do that like this:

container.RegisterType<IMyManager, MyManager>();

But, that's not the issue.

One fix I did was a circular dependency. I changed all involved constructors and methods to use property values, not instances. I checked all involved classes and there are no longer any circular dependencies.

Yet, the problem still occurs.

The question

What can I do to find out the actual problem? Manually checking dependencies is way too much overhead, because the structure is an intricate web of deeper dependencies. And this will get worse as the app matures.

Alternatively, if Unity just always obscures these messages (without being able to fix that), are there alternatives out there that do provide worthwhile error information?

UPDATE

Per request, the full error message (though I don't think the stacktrace is very helpful):

{"Message":"An error has occurred.","ExceptionMessage":"An error occurred when trying to create a controller of type 'MyController'. 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.<SendAsync>d__1.MoveNext()","InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Type 'MyProject.Web.Api.Controllers.MyController' 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)"}}

UPDATE 2

I dug a little deeper and checked all dependencies (they are pretty massive), but everything is registered and loaded correctly. There also aren't any circular dependencies, so as far as I can tell everything 'should' work. Since it doesn't I conclude that there's some error happening that is not being thrown up.

Spikee
  • 3,967
  • 7
  • 35
  • 68
  • Most of the times Unity puts a detailed exception in a chain where you have an exception with inner exception and inner exception and the very last one is actual issue. Doesn't it behave like this in your case? – Wiktor Zychla Oct 14 '15 at 10:08
  • Take a look at this related q/a: https://stackoverflow.com/a/15910758/264697. Just replace the words "Web API" with "MVC" and "Simple Injector" with "Unity" and you'll have a good description about what is going on here. TLDR; Register your controllers explicitly. – Steven Oct 14 '15 at 10:17
  • Unity doesn't hide any errors and the errors that you're encountering are errors produced by Unity from what I can see. It sounds like you don't have your WebAPI hooked up for dependency injection. You have to configure it to use the same container if you haven't already. Does dependency injection work in any of your WebAPI controllers, or is this the first one? – Luke Oct 14 '15 at 10:18
  • Note that you should post the complete exception information + stack trace, because that often contains crucial information telling us more about what's going on. Without this information, we will just be guessing. – Steven Oct 14 '15 at 10:20

4 Answers4

9

If the error says that you need a parameterless constructor, that suggests to me that Unity isn't registered for WebAPI, even though it is registered for your ASP.NET MVC application. If your IoC is working correctly, it shouldn't need a paramaterless constructor, because it should be able to resolve the dependencies that exist within your controller's constructor.

WebAPI has it's own pipeline to ASP.NET MVC for example WebAPI can be OWIN hosted, hence why it needs hooking up separately even if they exist in the same project.

You should hook your WebAPI to the dependency resolver within your UnityConfig, I believe that there is an example here: http://www.devtrends.co.uk/blog/using-unity.mvc5-and-unity.webapi-together-in-a-project

using Microsoft.Practices.Unity;
using System.Web.Http;
using System.Web.Mvc;

namespace WebApplication1
{
    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>();

            // Configures container for ASP.NET MVC
            DependencyResolver.SetResolver(new Unity.Mvc5.UnityDependencyResolver(container));

            // Configures container for WebAPI
            GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
        }
    }
}

In the example above there are two lines for configuration, but they share the same container and thus the same bindings - you don't have to define them twice. If you ever came to separate the WebAPI project from the ASP.NET MVC one, then you would have to have a separate container and bindings.

In terms of finding the problem, or Unity hiding errors from you, in my experience this simply isn't the case. The error that you're experiencing is straight from ASP.NET MVC. In normal use without an IoC, you need a parameterless constructor... with an IoC it controls the creation of the controllers and thus resolves the dependencies.

Luke
  • 22,826
  • 31
  • 110
  • 193
  • @downvoter I'd appreciate a note so that I can improve the answer - thanks – Luke Oct 14 '15 at 10:40
  • I'm not the downvoter (I don't have the privilege yet) but it's not a good answer because I said IoC did work just fine before adding new functionality. There's 'something' going wrong in new development, not the existing code. – Spikee Oct 14 '15 at 11:15
  • @Spikee Please answer the following questions: How many WebAPI controllers do you have in your project? How many of them are currently working with dependency injection? Please detail how you are hooking your WebAPI controllers up to your Unity container. Then we can judge if this is a good answer or not... – Luke Oct 14 '15 at 11:17
  • All controllers work with injected parameters, with instances being thrown in that have further dependencies forming a structure too complex to summarize here. – Spikee Oct 14 '15 at 11:25
  • Can you at least answer all of the questions. Bare in mind that WebAPI controllers are not the same as ASP.NET MVC controllers. I don't want details of the bindings, just how you are currently assigning your dependency resolver to WebAPI. Please add this to your question. – Luke Oct 14 '15 at 11:26
  • For .NET Framework 4.5 onwards, just add [this NuGet package](https://www.nuget.org/packages/Unity.Mvc/) to your ASP.NET MVC project and it will automatically add a static class called `UnityMvcActivator` with everything required. You don't have to do anything else. You can remove your own calls to `DependencyResolver.SetResolver`, and certainly remove any references you have to Unity.MvcX by Paul Hiles. – Neo Sep 19 '18 at 10:34
  • 1
    @Luke Sorry, I should've been clearer in that I was referring to the code in the answer referencing ASP.NET MVC. The Web API configuration will still be needed. – Neo Sep 19 '18 at 10:49
  • This was it for me! Thanks! – letie May 02 '19 at 20:10
2

I found it, the problem was that I am remaking existing code, in the same solution, meaning that there's going to be duplicate files with identical names.

In this particular case I had an interface that was exactly the same as a previously existing one. Somewhere deep in the code I used the wrong namespace, meaning that the IoC mapping was incorrect.

So, something like this:

I have:

old.managers.IMyManager

and

new.managers.IMyManager

What I was doing in the mapping was:

container.RegisterType<IMyManager, MyManager>();

where IMyManager in this case is new.managers.IMyManager, as it should be.

One of the consumers of this dependency expected IMyManager of namespace old.managers.

Updating the consumer to use the new namespace fixed it.

Spikee
  • 3,967
  • 7
  • 35
  • 68
  • This doesn't make sense, how would the namespace of an interface that you use in your bindings fix the error `Make sure that the controller has a parameterless public constructor.`? You must have changed the configuration. – Luke Jan 05 '16 at 13:59
  • It's been a while but: If my constructor is expecting a parameter of type `new.managers.IMyManager` and my binding is done for `old.managers.IMyManager`, it's never going to arrive at the constructor because there's a significant difference in definition. It's just hard to notice at face value. A parameter that's not identified means the signature of the constructor wasn't matched. Meaning it looks for the default parameterless constructor. Which does not exist, on purpose. – Spikee Jan 05 '16 at 19:55
  • Strange, generally if this is the case, the IoC container will recognise that it was unable to bind an interface and produce a specific error message accordingly. The parameterless constructor error message is produced by the MVC framework itself when it can't create an instance of a controller. – Luke Jan 06 '16 at 07:54
  • Come on man, this question hasn't been touched since october and yesterday I get a downvote at around the same time as your response. But whatever. – Spikee Jan 06 '16 at 07:59
0

Don't forget this in your web.config

<system.web>
    <compilation targetFramework="4.8" />
    <httpRuntime targetFramework="4.8" />
    <customErrors mode="Off" />
</system.web>

Missing the httpRuntime targetFramework="4.8" part will cause the parameterless public constructor error

user2282308
  • 33
  • 1
  • 7
-5

I think you should add another constructor for your controller.

public MyController() {}

If it still error, you should check the components that register for Application_Start (in Global.asax). In UnityConfig.cs :

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

        container.RegisterType<IMyManager, MyManager>();

        MvcUnityContainer.Container = container;

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));
    }

Make the default for controller.

public class UnityControllerFactory : DefaultControllerFactory
{
    public override IController CreateController(RequestContext requestContext, string controllerName)
    {
        Type controllerType = null;
        if (TypeHelper.LooksLikeTypeName(controllerName))
        {
            controllerType = TypeHelper.GetType(controllerName);
        }

        if (controllerType == null)
        {
            controllerType = this.GetControllerType(requestContext, controllerName);
        }

        return controllerType != null ? this.GetControllerInstance(requestContext, controllerType) : null;
    }

    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        try
        {
            if (controllerType == null)
                throw new ArgumentNullException("controllerType");

            if (!typeof(IController).IsAssignableFrom(controllerType))
                throw new ArgumentException(string.Format(
                    "Type requested is not a controller: {0}",
                    controllerType.Name),
                    "controllerType");

            return MvcUnityContainer.Container.Resolve(controllerType) as IController;
        }
        catch
        {
            return null;
        }
    }
}

public static class MvcUnityContainer
{
    public static IUnityContainer Container { get; set; }
}

In Application_Start() (Global.asax.cs and Global.asax)

UnityConfig.RegisterComponents();
Ken Nguyen
  • 95
  • 10
  • 3
    That's addressing the symptom, not the issue. And then you will get null reference errors because your dependencies are not being injected. – Spikee Oct 14 '15 at 11:05
  • In my project, I have two the constructors. public MyController(IMyManager myManager) { this.MyManager myManager; } and public MyController() {}. It work fine. – Ken Nguyen Oct 15 '15 at 02:20
  • 1
    How do you instantiate dependencies if the default constructor is used? – Spikee Oct 15 '15 at 06:18
  • IOC is rendered useless with your suggestion – birwin Aug 08 '18 at 22:54