是否有人使用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);
}
}
我似乎永远不会在我的Unity文件中查找解析依赖项,并且我收到如下错误:
尝试创建类型的控制器时发生错误 'PersonalShopper.Services.WebApi.Controllers.ShoppingListController'。 确保控制器具有无参数的公共构造函数。
在 System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpControllerContext controllerContext,类型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) 请求,取消语音取消语句) 在System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage) 请求,取消语音取消语言)
控制器看起来像:
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中,控制器工厂会发现需要解析依赖关系。
好像我的控制器工厂从未被调用过。
答案 0 :(得分:42)
想出来。
对于 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.
});
}
答案 1 :(得分:37)
有一个更好的解决方案在这里正常工作
http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver
答案 2 :(得分:22)
您可能需要查看Unity.WebApi NuGet包,它将对所有这些进行排序,并且还可以满足IDisposable组件的需要。
见
http://nuget.org/packages/Unity.WebAPI
或
http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package
答案 3 :(得分:9)
Microsoft为此创建了一个包。
从包管理器控制台运行以下命令。
install-package Unity.AspNet.WebApi
如果您已安装Unity,则会询问您是否要覆盖App_Start \ UnityConfig.cs。回答否并继续。
无需更改任何其他代码,DI(带统一)将起作用。
答案 4 :(得分: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无法解决控制器中依赖关系的问题
答案 5 :(得分:2)
在最近的RC中,我发现不再有SetResolver方法。要启用IoC for controller和webapi,我使用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魔术。 ;)
答案 6 :(得分:2)
在阅读完答案之后,我仍然需要做很多工作才能找到这个问题,所以这里是为了同行的利益: 这就是您在ASP.NET 4 Web API RC中所需要做的所有事情(截至2013年8月8日):
瞧,您可以在没有其他代码行的情况下将依赖项注入构造函数中!
注意:我从其作者的THIS博客中的一条评论中获得了此信息。
答案 7 :(得分:1)
我抛出了同样的异常,在我的情况下,我在MVC3和MVC4二进制文件之间发生了冲突。这阻止了我的控制器与我的IOC容器正确注册。检查你的web.config并确保它指向正确版本的MVC。
答案 8 :(得分: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
答案 9 :(得分:0)
使用Unity.WebAPI NuGet包时遇到了同样的问题。问题是该软件包从未在我的Global.asax中添加对UnityConfig.RegisterComponents()
的调用。
Global.asax.cs应如下所示:
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
UnityConfig.RegisterComponents();
...
}
}
答案 10 :(得分:0)
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 - &gt; WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
UnityConfig.ConfigureUnity(config);
...
现在它会起作用。
原始来源但有点修改: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection