2012-03-02 126 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

相關問題