无法使用 Unity 将依赖项注入 ASP.NET Web API 控制器
Posted
技术标签:
【中文标题】无法使用 Unity 将依赖项注入 ASP.NET Web API 控制器【英文标题】:Cannot Inject Dependencies into ASP.NET Web API Controller using Unity 【发布时间】:2012-03-20 15:25:47 【问题描述】:有没有人成功地使用 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 控制器上下文,类型控制器类型) 在 System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance(HttpControllerContext 控制器上下文,HttpControllerDescriptor 控制器描述符) 在 System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController(HttpControllerContext 控制器上下文,字符串控制器名称) 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage 请求,CancellationToken 取消令牌) 在 System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage 请求,CancellationToken 取消令牌)
控制器看起来像:
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 中,控制器工厂会发现需要解决依赖关系。
似乎我的控制器工厂从未被调用过。
【问题讨论】:
【参考方案1】:我抛出了同样的异常,在我的例子中,我在 MVC3 和 MVC4 二进制文件之间存在冲突。这阻止了我的控制器在我的 IOC 容器中正确注册。检查您的 web.config 并确保它指向正确的 MVC 版本。
【讨论】:
这解决了我的 Razor 问题,但没有解决解决 api 控制器的问题。【参考方案2】:想通了。
对于 ApiControllers,MVC 4 使用 System.Web.Http.Dispatcher.IHttpControllerFactory 和 System.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.
);
【讨论】:
你是如何实现GlobalConfiguration.Configuration.ServiceResolver.SetResolver()
的 lamda 的?
这篇文章已经过时了。请参阅 CodeKata 的回复,了解使用 MVC RC 的更清洁的解决方案。
这已经过时了。 Microsoft 有一个使用 Web API 进行 DI 的 Nuget 包。看我的回答。【参考方案3】:
您可能想看看 Unity.WebApi NuGet 包,它将整理所有这些并满足 IDisposable 组件的需求。
见
http://nuget.org/packages/Unity.WebAPI
或
http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package
【讨论】:
这里有一篇很好的博文 (netmvc.blogspot.com/2012/04/…),其中介绍了使用 Unity.mvc3(也适用于 MVC4)和 Unit.WebApi 的组合来非常干净地实现 DI。跨度> 评论中提到的链接反映了更新的 API,对于现在遇到此问题的任何人:GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new Unity.WebApi.UnityDependencyResolver(container));现在是 GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); 请注意,它还提供比自定义UnityResolver
更好的调试消息。【参考方案4】:
这里有一个更好的解决方案可以正常工作
http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
【讨论】:
这是一个使用 MVC RC 的更好的解决方案。您不需要提供 IHttpControllerActivator 的实现。您改为实现 System.Web.Http.Dependencies.IDependencyResolver。 不太喜欢链接到博客 - 你能在这里总结一下并放上链接吗? :) 这看起来是一个不错的方法,但我遇到了几个错误,如下所示。看起来新的解析器无法解析多种类型。依赖项解析失败,type = "System.Web.Http.Hosting.IHostBufferPolicySelector",name = "(none)"。异常发生时:解决时。例外是: InvalidOperationException - IHostBufferPolicySelector 类型没有可访问的构造函数。 --- 异常时,容器为:Resolving System.Web.Http.Hosting.IHostBufferPolicySelector,( 微软有一个 Nuget 包,它使用 Web API 进行 DI。看我的回答。【参考方案5】:在最近的一次 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 魔术。 ;)
【讨论】:
使用requestContext.Configuration.DependencyResolver.GetService()不是更好吗?【参考方案6】:阅读答案后,我仍然需要做很多挖掘才能找到这个问题,所以这里是为了同行的利益: 这就是您在 ASP.NET 4 Web API RC 中需要做的所有事情(截至 2013 年 8 月 8 日):
-
添加对“Microsoft.Practices.Unity.dll”的引用 [我正在使用版本
3.0.0.0,通过 NuGet 添加]
添加对“Unity.WebApi.dll”的引用[我使用的是 0.10.0.0 版,通过 NuGet 添加]
使用容器注册您的类型映射 - 类似于 Unity.WebApi 项目添加到您的项目中的 Bootstrapper.cs 中的代码。
在从 ApiController 类继承的控制器中,创建参数化构造函数,将其参数类型作为映射类型
您瞧,您无需另一行代码即可将依赖项注入到构造函数中!
注意:我从作者 THIS 博客中的一位 cmets 获得此信息。
【讨论】:
【参考方案7】:我在使用 Unity.WebAPI NuGet 包时遇到了同样的问题。问题是该包从未在我的 Global.asax 中添加对 UnityConfig.RegisterComponents()
的调用。
Global.asax.cs 应如下所示:
public class WebApiApplication : System.Web.HttpApplication
protected void Application_Start()
UnityConfig.RegisterComponents();
...
【讨论】:
【参考方案8】:由于向 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://***.com/a/26624602/1350747
【讨论】:
【参考方案9】:微软为此创建了一个包。
从包管理器控制台运行以下命令。
安装包 Unity.AspNet.WebApi
如果您已经安装了 Unity,它会询问您是否要覆盖 App_Start\UnityConfig.cs。回答否并继续。
无需更改任何其他代码,DI(具有统一性)即可工作。
【讨论】:
你能告诉我为什么当 nuget 提示覆盖 UnityConfig.cs 时我们回答“否”吗?问题2:有没有使用Unity.AspNet.WebApi的示例代码? 抱歉,我已更改为 Autofac,因为我需要一些 Unity 无法轻松完成的事情,而 Autofac 开箱即用。但是从记忆中你需要说不,如果你已经安装了统一,因为你不想覆盖你已经工作的统一配置,你只想添加统一的 webapi 配置。在 webapi 中使用 unity 正是您正常使用它的方式。如果它没有像其他类那样注入您的依赖项,我建议发布一个问题。注入 webapi 的方式与其他类(如控制器)没有什么不同 @garethb:我正在使用 unity.webapi,但必须在单元测试中添加几行代码来解析我不喜欢的 ControllerContext。假设,如果我使用 Unity.AspNet.WebApi,该地址会自动从 UnitTests 项目中解析 ControllerContext 吗?请建议 我不这么认为。很确定两者都以类似的方式工作。我在单元测试中创建了一个新的模拟上下文。 @garethb:感谢您的快速回复。嘲笑奏效了。我无法使用 Unity.WebApi 或 Unity.Aspnet.webapi 注入 UrlHelper。你还记得你在使用 Unity 时是怎么做的吗?提前谢谢你【参考方案10】:我遇到了同样的错误,并在互联网上搜索了几个小时的解决方案。最终,我似乎必须在调用 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 无法解决我的控制器中的依赖项的问题
【讨论】:
【参考方案11】:ASP.NET Web API 2 的简短摘要。
从 NuGet 安装 Unity
。
创建一个名为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
【讨论】:
以上是关于无法使用 Unity 将依赖项注入 ASP.NET Web API 控制器的主要内容,如果未能解决你的问题,请参考以下文章
csharp 将Castle Windsor依赖项注入ASP.NET Web API过滤器C#