Unity IoC 不会将依赖项注入 Web API Controller

Unity IoC does not inject dependency into Web API Controller

我刚开始使用 Unity,但我的问题是每当我调用我的 Web 服务时,我都会收到一个异常说明

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

我已经学习了多个教程,但仍然遇到同样的问题。

在我的 WebApiConfig class 的注册函数中,我有

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

这是我的 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();
    }
}

我没有注册任何控制器,因为每个教程都声称我不需要这样做。这是我的实际控制人

public class Controller: ApiController
{
    private IValidator _validator;

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

    [HttpPost]
    public void ReceiveIPN()
    {

    }
}

有人知道我可能做错了什么吗?谢谢!

编辑 1:这是验证器 class 的 "implementation"。它很空,因为在解决 Unity 问题之前我不想在这里引入错误。

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


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

编辑 2:这是我尝试使用 Fiddler

调用网络 api 路由时得到的完整错误响应

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

您的 Unity 容器可能正在处理,因为它仅在您的 WebApiConfig.Register() 方法的范围内定义。如果您将容器定义为 Global 的成员,它将在应用程序的整个生命周期内保留您的容器,它应该可以工作。

编辑:也不要忘记在 Application_End 上处理容器。

所以,在用头撞墙几个小时后,我发现这不起作用,因为我的项目中有一个 OWIN/Katana Startup.cs class。现在我不知道这里到底发生了什么,所以如果能提供更多信息就更好了。

基本上,因为我使用的是 OWIN/Katana,所以我有一个 Startup.cs 文件,它创建了一个新的 HttpConfiguration 对象并对其进行了配置,类似于 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();
}

看起来代码首先通过 WebApiConfig 的 Register 函数运行,然后用 Startup.cs 文件中生成的对象覆盖 HttpConfiguration 对象。我必须将我的容器设置内容移到这里才能使其正常工作。

抱歉我之前没有提到 OWIN 的东西。这对我来说是相当新的,我没有意识到它是相关的。希望这可以避免其他人遭受我刚刚经历的痛苦。

我知道这是一个旧的 post 但由于我 运行 遇到了同样的问题,解决方案是简单地将配置对象传递给 Unity 注册函数并使用其中的 DependencyResolver实例:

编辑: 刚刚注意到已接受的答案确实如此......对于垃圾邮件感到抱歉;-)

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);
    }
}
  • 通过nuget包在项目中安装Unity.mvc5和Unity.WebApi
  • 按照下行指定全命名空间

示例:

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