Unity IoC does not inject dependency into Web API Controller

别等时光非礼了梦想. 提交于 2019-11-28 02:29:48

问题


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)"}}


回答1:


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.




回答2:


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.




回答3:


  • 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);
    }
}



回答4:


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);
    }
}


来源:https://stackoverflow.com/questions/29611083/unity-ioc-does-not-inject-dependency-into-web-api-controller

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!