83

有没有人成功使用 IoC 容器将依赖项注入 ASP.NET WebAPI 控制器?我似乎无法让它工作。

这就是我现在正在做的事情。

在我的global.ascx.cs

    public static void RegisterRoutes(RouteCollection routes)
    {
            // code intentionally omitted 
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = BuildUnityContainer();

        System.Web.Http.GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
            t =>
            {
                try
                {
                    return container.Resolve(t);
                }
                catch (ResolutionFailedException)
                {
                    return null;
                }
            },
            t =>
            {
                try
                {
                    return container.ResolveAll(t);
                }
                catch (ResolutionFailedException)
                {
                    return new System.Collections.Generic.List<object>();
                }
            });

        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); 

        BundleTable.Bundles.RegisterTemplateBundles();
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer().LoadConfiguration();

        return container;
    }

我的控制器工厂:

public class UnityControllerFactory : DefaultControllerFactory
            {
                private IUnityContainer _container;

                public UnityControllerFactory(IUnityContainer container)
                {
                    _container = container;
                }

                public override IController CreateController(System.Web.Routing.RequestContext requestContext,
                                                    string controllerName)
                {
                    Type controllerType = base.GetControllerType(requestContext, controllerName);

                    return (IController)_container.Resolve(controllerType);
                }
            }

它似乎从来没有查看我的统一文件来解决依赖关系,并且我收到如下错误:

尝试创建“PersonalShopper.Services.WebApi.Controllers.ShoppingListController”类型的控制器时出错。确保控制器有一个无参数的公共构造函数。

在 System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpControllerContext controllerContext, Type controllerType) 在 System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance(HttpControllerContext controllerContext, HttpControllerDescriptor controllerDescriptor) 在 System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController (HttpControllerContext controllerContext, String controllerName) 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancelToken) 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancelToken)

控制器看起来像:

public class ShoppingListController : System.Web.Http.ApiController
    {
        private Repositories.IProductListRepository _ProductListRepository;


        public ShoppingListController(Repositories.IUserRepository userRepository,
            Repositories.IProductListRepository productListRepository)
        {
            _ProductListRepository = productListRepository;
        }
}

我的统一文件如下所示:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <container>
    <register type="PersonalShopper.Repositories.IProductListRepository, PersonalShopper.Repositories" mapTo="PersonalShopper.Implementations.MongoRepositories.ProductListRepository, PersonalShopper.Implementations" />
  </container>
</unity>

请注意,我没有控制器本身的注册,因为在以前版本的 mvc 中,控制器工厂会发现需要解决依赖关系。

似乎我的控制器工厂从未被调用过。

4

11 回答 11

43

弄清楚了。

对于ApiControllers,MVC 4 使用System.Web.Http.Dispatcher.IHttpControllerFactorySystem.Web.Http.Dispatcher.IHttpControllerActivator创建控制器。如果没有静态方法来注册这些它们的实现是什么;当它们被解析时,mvc 框架在依赖解析器中查找实现,如果找不到,则使用默认实现。

通过执行以下操作,我得到了控制器依赖项的统一解析:

创建了一个 UnityHttpControllerActivator:

public class UnityHttpControllerActivator : IHttpControllerActivator
{
    private IUnityContainer _container;

    public UnityHttpControllerActivator(IUnityContainer container)
    {
        _container = container;
    }

    public IHttpController Create(HttpControllerContext controllerContext, Type controllerType)
    {
        return (IHttpController)_container.Resolve(controllerType);
    }
}

将该控制器激活器注册为统一容器本身中的实现:

protected void Application_Start()
{
    // code intentionally omitted

    IUnityContainer container = BuildUnityContainer();
    container.RegisterInstance<IHttpControllerActivator>(new UnityHttpControllerActivator(container));

    ServiceResolver.SetResolver(t =>
       {
         // rest of code is the same as in question above, and is omitted.
       });
}
于 2012-03-03T06:38:28.350 回答
38

有一个更好的解决方案可以在这里正常工作

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

于 2012-05-14T23:45:52.307 回答
24

您可能想看看 Unity.WebApi NuGet 包,它将整理所有这些并满足 IDisposable 组件的需求。

http://nuget.org/packages/Unity.WebAPI

或者

http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package

于 2012-03-20T16:30:34.050 回答
10

微软为此创建了一个包。

从包管理器控制台运行以下命令。

安装包 Unity.AspNet.WebApi

如果您已经安装了 Unity,它会询问您是否要覆盖 App_Start\UnityConfig.cs。回答否并继续。

无需更改任何其他代码,DI(具有统一性)将起作用。

于 2015-05-20T22:48:07.320 回答
3

我有同样的错误,并在互联网上搜索了几个小时的解决方案。最终,我似乎必须在调用 WebApiConfig.Register 之前注册 Unity。我的 global.asax 现在看起来像

public class WebApiApplication : System.Web.HttpApplication
{
   protected void Application_Start()
   {
       UnityConfig.RegisterComponents();
       AreaRegistration.RegisterAllAreas();
       GlobalConfiguration.Configure(WebApiConfig.Register);
       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
       RouteConfig.RegisterRoutes(RouteTable.Routes);
       BundleConfig.RegisterBundles(BundleTable.Bundles);
   }
}

对我来说,这解决了 Unity 无法解决我的控制器中的依赖项的问题

于 2016-04-14T22:37:59.923 回答
2

在最近的一个 RC 中,我发现不再有 SetResolver 方法。要同时为控制器和 webapi 启用 IoC,我使用 Unity.WebApi (NuGet) 和以下代码:

public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();

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

        ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new ControllerActivator()));
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.Configure(c => c.Scan(scan =>
        {
            scan.AssembliesInBaseDirectory();
            scan.With<UnityConfiguration.FirstInterfaceConvention>().IgnoreInterfacesOnBaseTypes();
        }));

        return container;
    }
}

public class ControllerActivator : IControllerActivator
{
    IController IControllerActivator.Create(RequestContext requestContext, Type controllerType)
    {
        return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as IController;
    }
}

我还将 UnityConfiguration(也来自 NuGet)用于 IoC 魔术。;)

于 2012-07-06T12:33:31.297 回答
2

阅读答案后,我仍然需要做很多挖掘才能找到这个问题,所以这是为了同行的利益:这就是你在 ASP.NET 4 Web API RC 中需要做的所有事情(截至 8 月 8 日) '13):

  1. 添加对“Microsoft.Practices.Unity.dll”的引用[我在版本 3.0.0.0,通过 NuGet 添加]
  2. 添加对“Unity.WebApi.dll”的引用[我在版本 0.10.0.0,通过 NuGet 添加]
  3. 使用容器注册您的类型映射 - 类似于 Unity.WebApi 项目添加到您的项目中的 Bootstrapper.cs 中的代码。
  4. 在从 ApiController 类继承的控制器中,创建参数化构造函数,其参数类型为映射类型

瞧,您无需另一行代码即可将依赖项注入到构造函数中!

注意:我从博客作者的评论中获得了此信息。

于 2013-08-08T10:41:11.663 回答
2

ASP.NET Web API 2 的简短摘要。

Unity从 NuGet安装。

创建一个名为的新类UnityResolver

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()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        container.Dispose();
    }
}

创建一个名为的新类UnityConfig

public static class UnityConfig
{
    public static void ConfigureUnity(HttpConfiguration config)
    {
        var container = new UnityContainer();
        container.RegisterType<ISomethingRepository, SomethingRepository>();
        config.DependencyResolver = new UnityResolver(container);
    }
}

编辑 App_Start -> WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    UnityConfig.ConfigureUnity(config);
    ...

现在它将起作用。

原始来源但稍作修改: https ://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection

于 2017-06-20T13:15:34.853 回答
1

我抛出了同样的异常,在我的例子中,我在 MVC3 和 MVC4 二进制文件之间存在冲突。这阻止了我的控制器在我的 IOC 容器中正确注册。检查您的 web.config 并确保它指向正确的 MVC 版本。

于 2012-03-02T16:14:56.070 回答
1

由于向 Unity 注册控制器,会出现此问题。我通过使用约定注册解决了这个问题,如下所示。请根据需要过滤掉任何其他类型。

    IUnityContainer container = new UnityContainer();

    // Do not register ApiControllers with Unity.
    List<Type> typesOtherThanApiControllers
        = AllClasses.FromLoadedAssemblies()
            .Where(type => (null != type.BaseType)
                           && (type.BaseType != typeof (ApiController))).ToList();

    container.RegisterTypes(
        typesOtherThanApiControllers,
        WithMappings.FromMatchingInterface,
        WithName.Default,
        WithLifetime.ContainerControlled);

上面的例子也使用AllClasses.FromLoadedAssemblies(). 如果您正在查看从基本路径加载程序集,它可能无法在使用 Unity 的 Web API 项目中按预期工作。请看我对与此相关的另一个问题的回答。https://stackoverflow.com/a/26624602/1350747

于 2014-11-06T10:43:58.140 回答
0

使用 Unity.WebAPI NuGet 包时我遇到了同样的问题。问题是这个包从来没有UnityConfig.RegisterComponents()在我的 Global.asax 中添加过调用。

Global.asax.cs 应如下所示:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        UnityConfig.RegisterComponents();
        ...
    }
}
于 2014-10-08T14:57:19.413 回答