2012-03-02 127 views
73

有没有人使用IoC容器向ASP.NET WebAPI控制器注入依赖关系的任何成功?我似乎无法得到它的工作。使用Unity无法注入ASP.NET Web API控制器的依赖关系

这就是我现在要做的。

在我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,类型controllerType) 在System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance(HttpControllerContext controllerContext,HttpControllerDescriptor controllerDescriptor) 在系统。 Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController(HttpControllerContext controllerContext,字符串controllerName) 在System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage 请求,的CancellationToken的CancellationToken) 在System.Web.Ht tp.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage 请求的CancellationToken的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中,控制器工厂会发现需要解决的依赖关系。

这似乎是我的控制器工厂从未被称为。

回答

38

想通了。

对于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. 
     }); 
} 
+0

你是如何为'GlobalConfiguration.Configuration.ServiceResolver.SetResolver()'实现lamda的? – jrummell 2012-03-14 13:15:07

+0

该代码在原始问题中。 – 2012-03-14 22:52:22

+2

是的,它当然是。我没有阅读。 – jrummell 2012-03-15 13:01:28

1

我有同样的异常被抛出,在我的情况下,我有一个MVC3和MVC4二进制文件之间的冲突。这阻止了我的控制器被我的IOC容器正确注册。检查你的web.config并确保它指向正确版本的MVC。

+0

这个固定我的剃须刀的问题,但没有解决解决API控制器的问题。 – 2012-03-03 15:14:41

22

你可能想看看Unity.WebApi的NuGet包,它将把所有这些都整理出来,同时也为IDisp osable组件。

看到

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

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

+2

这里有一篇很好的博客文章(http://netmvc.blogspot.com/2012/04/dependency-injection-in-aspnet-mvc-4.html),有一个使用Unity组合的演练。mvc3(也适用于MVC4)和Unit.WebApi,可以很干净地实现DI。 – 2012-08-25 20:52:10

+1

评论中提到的链接反映了更新的API,对于任何现在遇到此问题的人: GlobalConfiguration.Configuration.ServiceResolver.SetResolver( new Unity.WebApi.UnityDependencyResolver(container)); 现在是 GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container); – 2013-05-13 16:07:12

+0

注意,它还提供了比自定义的'UnityResolver'更好的调试消息。 – 2015-09-16 07:01:27

35
+1

这是MVC RC更好的解决方案。你不需要提供IHttpControllerActivator的实现。改为实现System.Web.Http.Dependencies.IDependencyResolver。 – 2012-06-29 15:24:35

+21

不是链接到博客的忠实粉丝 - 你能在这里总结并把链接? :) – 2014-04-12 00:22:05

+2

它看起来像一个很好的方法,但我收到像以下几个错误。看起来新的解析器无法解析多种类型。解析依赖失败,type =“System.Web.Http.Hosting.IHostBufferPolicySelector”,name =“(none)”。 发生异常时:解析时。 异常是:InvalidOperationException - 类型IHostBufferPolicySelector没有可访问的构造函数。 --- 在异常时,容器是: 解决System.Web.Http.Hosting.IHostBufferPolicySelector,( – ATHER 2015-01-15 23:01:23

2

工作在A R ecent RC,我发现不再有SetResolver方法。要同时启用国际奥委会控制器的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)政府间海洋学委员会魔法。 ;)

+0

止跌”。你最好使用requestContext.Configuration.DependencyResolver.GetService()? – Alwyn 2013-03-27 01:57:18

2

在阅读答案后,我仍然不得不在这个问题上进行大量的研究,所以这里是为了同行的利益: 这就是你需要在ASP.NET 4 Web中完成的所有工作API RC(如在8月8日'13):

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

罗参构造函数,你看,你注入你的构造函数的依赖,而不另一行代码!

注意:我从其作者之一的THIS博客的评论中获得此信息。

0

我在使用Unity.WebAPI NuGet包时遇到了同样的问题。问题是该包从未在我的Global.asax中添加对UnityConfig.RegisterComponents()的调用。

的Global.asax.cs应该是这样的:发生是由于与统一登记控制器

public class WebApiApplication : System.Web.HttpApplication 
{ 
    protected void Application_Start() 
    { 
     UnityConfig.RegisterComponents(); 
     ... 
    } 
} 
1

此问题。我通过按照惯例使用注册来解决此问题,如下所示。请根据需要滤除任何其他类型。

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

微软已经为此创建了一个包。

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

安装包Unity.AspNet.WebApi

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

无需更改任何其他代码和DI(与统一)将工作。

+0

你可以让我知道为什么我们在nuget提示覆盖UnityConfig.cs时回答'no'问题2:是否有一些使用Unity的示例代码。 AspNet.WebApi? – 2015-10-10 14:09:29

+0

对不起,我已经改成了Autofac,因为有一些事情我需要Unity,Unity并没有那么容易,Autofac也是这样做的,但是从内存来说,如果你已经安装了Unity,你需要说不。不想覆盖你已经工作的统一配置,你只想添加统一的webapi配置o在webapi中使用统一就是你通常使用它的方式。如果它没有像其他类一样注入你的依赖项,我会建议发布一个问题。有没有不同的方式注入webapi比其他类(如控制器) – garethb 2015-10-12 03:01:06

+0

@garethb:我使用unity.webapi,但必须在单元测试中添加几行代码来解决ControllerContext,我不喜欢。假设,如果我使用Unity.AspNet.WebApi,该地址是否可以从UnitTests项目中自动解析ControllerContext?请建议 – sam 2016-04-26 22:08:51

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

对我来说,这个问题得到了解决团结无法解析的依赖在我的控制器

0

短片摘要的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

相关问题