C# 无法使用 Unity 将依赖项注入 ASP.NET Web API 控制器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9527988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Cannot Inject Dependencies into ASP.NET Web API Controller using Unity
提问by Oved D
Has anyone had any success running using an IoC container to inject dependencies into ASP.NET WebAPI controllers? I cannot seem to get it to work.
有没有人成功地使用 IoC 容器将依赖项注入 ASP.NET WebAPI 控制器?我似乎无法让它工作。
This is what I'm doing now.
这就是我现在正在做的。
In my global.ascx.cs:
在我的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;
}
My controller factory:
我的控制器工厂:
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);
}
}
It never seems to look in my unity file to resolve dependencies, and I get an error like:
它似乎从不查看我的统一文件来解决依赖关系,我收到如下错误:
An error occurred when trying to create a controller of type 'PersonalShopper.Services.WebApi.Controllers.ShoppingListController'. Make sure that the controller has a parameterless public constructor.
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpControllerContext controllerContext, Type controllerType) at System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance(HttpControllerContext controllerContext, HttpControllerDescriptor controllerDescriptor) at System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController(HttpControllerContext controllerContext, String controllerName) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
尝试创建类型为“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) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request, CancellationToken cancelationToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancelationToken)
Controller looks like:
控制器看起来像:
public class ShoppingListController : System.Web.Http.ApiController
{
private Repositories.IProductListRepository _ProductListRepository;
public ShoppingListController(Repositories.IUserRepository userRepository,
Repositories.IProductListRepository productListRepository)
{
_ProductListRepository = productListRepository;
}
}
My unity file looks like:
我的统一文件看起来像:
<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>
Note that I don't have a registration for the controller itself because in previous versions of mvc the controller factory would figure out that the dependencies needed to be resolved.
请注意,我没有为控制器本身注册,因为在以前版本的 mvc 中,控制器工厂会发现需要解决依赖关系。
It seems like my controller factory is never being called.
似乎我的控制器工厂从未被调用过。
采纳答案by Oved D
Figured it out.
弄清楚了。
For ApiControllers, MVC 4 uses a System.Web.Http.Dispatcher.IHttpControllerFactoryand System.Web.Http.Dispatcher.IHttpControllerActivatorto create the controllers. If there is no static method to register what the implementation of these they are; when they are resolved, the mvc framework looks for the implementations in the dependency resolver, and if they are not found, uses the default implementations.
对于ApiControllers,MVC 4 使用System.Web.Http.Dispatcher.IHttpControllerFactory和System.Web.Http.Dispatcher.IHttpControllerActivator来创建控制器。如果没有静态方法来注册这些它们的实现是什么;当它们被解析时,mvc 框架会在依赖解析器中查找实现,如果没有找到,则使用默认实现。
I got unity resolution of controller dependencies working by doing the following:
我通过执行以下操作获得了控制器依赖项的统一解析:
Created a UnityHttpControllerActivator:
创建了一个 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);
}
}
Registered that controller activator as the implementation in the unity container itself:
将该控制器激活器注册为统一容器本身中的实现:
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.
});
}
回答by Oved D
I had the same exception being thrown, and in my case I had a conflict between MVC3 and MVC4 binaries. This was preventing my controllers from being registered properly with my IOC container. Check your web.config and make sure it's pointed to the correct versions of MVC.
我抛出了同样的异常,就我而言,MVC3 和 MVC4 二进制文件之间存在冲突。这阻止了我的控制器在我的 IOC 容器中正确注册。检查您的 web.config 并确保它指向正确的 MVC 版本。
回答by Paul Hiles
You might want to take a look at the Unity.WebApi NuGet package which will sort all this out and also cater for IDisposable components.
您可能想看看 Unity.WebApi NuGet 包,它将整理所有这些并满足 IDisposable 组件的需求。
see
看
http://nuget.org/packages/Unity.WebAPI
http://nuget.org/packages/Unity.WebAPI
or
或者
http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package
http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package
回答by CodeKata
There is a better solution that works correctly here
有一个更好的解决方案可以在这里正常工作
http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
回答by Noogen
In a recent RC, I find that there is no longer a SetResolver method. To enable both IoC for controller and webapi, I use Unity.WebApi (NuGet) and the following code:
在最近的 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;
}
}
I also use UnityConfiguration (also from NuGet) for IoC magic. ;)
我还使用 UnityConfiguration(也来自 NuGet)来实现 IoC 魔法。;)
回答by Sudhanshu Mishra
After reading the answers, I still had to do a lot of digging around to land at this gotcha so here it is for the benefit of peers: This is all you need to do in ASP.NET 4 Web API RC (as on 8th August '13):
阅读答案后,我仍然需要进行大量挖掘才能找到这个问题,所以这里是为了同行的利益:这就是您在 ASP.NET 4 Web API RC 中需要做的所有事情(截至 8 月 8 日) '13):
- Add a reference to "Microsoft.Practices.Unity.dll" [I'm on version 3.0.0.0, added through NuGet]
- Add a reference to "Unity.WebApi.dll" [I'm on version 0.10.0.0, added through NuGet]
- Register your type mappings with the container - similar to the code in Bootstrapper.cs that gets added to your project by Unity.WebApi project.
- In the controllers that inherit from the ApiController class, create parameterized constructors that have their parameter types as the mapped types
- 添加对“Microsoft.Practices.Unity.dll”的引用[我使用的是 3.0.0.0 版,通过 NuGet 添加]
- 添加对“Unity.WebApi.dll”的引用[我使用的是 0.10.0.0 版本,通过 NuGet 添加]
- 在容器中注册您的类型映射 - 类似于 Bootstrapper.cs 中的代码,该代码由 Unity.WebApi 项目添加到您的项目中。
- 在继承自 ApiController 类的控制器中,创建参数化构造函数,其参数类型作为映射类型
Lo and behold, you get the dependencies injected into your constructor without another line of code!
瞧,您无需另一行代码即可将依赖项注入到构造函数中!
NOTE: I got this information from one of the comments in THISblog by it's author.
注意:我从作者在此博客中的评论之一中获得了此信息。
回答by Keith
I had the same issue when using the Unity.WebAPI NuGet package. The problem was that the package never added a call to UnityConfig.RegisterComponents()in my Global.asax.
我在使用 Unity.WebAPI NuGet 包时遇到了同样的问题。问题是该包从未UnityConfig.RegisterComponents()在我的 Global.asax 中添加调用。
Global.asax.cs should look like this:
Global.asax.cs 应如下所示:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
UnityConfig.RegisterComponents();
...
}
}
回答by Srihari Sridharan
This issue occurs due to registering Controllers with Unity. I solved this by using registration by convention as shown below. Please filter out any additional types as required.
出现此问题是由于向 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);
Also the example above uses AllClasses.FromLoadedAssemblies(). If you are looking at loading assemblies from base path, it might not work as expected in a Web API project using Unity. Please take a look at my response to another question related to this. https://stackoverflow.com/a/26624602/1350747
上面的例子也使用AllClasses.FromLoadedAssemblies(). 如果您正在查看从基本路径加载程序集,它在使用 Unity 的 Web API 项目中可能无法按预期工作。请看一下我对另一个与此相关的问题的回答。https://stackoverflow.com/a/26624602/1350747
回答by garethb
Microsoft have created a package for this.
微软为此创建了一个包。
Run the following command from package manager console.
从包管理器控制台运行以下命令。
install-package Unity.AspNet.WebApi
安装包 Unity.AspNet.WebApi
If you already have Unity installed, it will ask if you want to overwrite App_Start\UnityConfig.cs. Answer no and continue.
如果您已经安装了 Unity,它会询问您是否要覆盖 App_Start\UnityConfig.cs。回答否并继续。
No need to change any other code and DI (with unity) will work.
无需更改任何其他代码,DI(统一)将起作用。
回答by Vincent
I had the same error and was searching the internet for solutions a couple of hours. Eventually it appeared that I had to register Unity BEFORE I was calling the WebApiConfig.Register. My global.asax now looks like
我遇到了同样的错误,并在互联网上搜索了几个小时的解决方案。最终似乎我必须在调用 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);
}
}
For me this solved the issue that Unity could not resolve the dependencies in my controllers
对我来说,这解决了 Unity 无法解决我的控制器中的依赖项的问题

