簡體   English   中英

無法使用Unity將依賴項注入ASP.NET Web API控制器

[英]Cannot Inject Dependencies into ASP.NET Web API Controller using Unity

有沒有人使用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,String controllerName)System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request,CancellationToken cancellationToken)at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage request,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版本中,控制器工廠會發現需要解決依賴關系。

好像我的控制器工廠從未被調用過。

弄清楚了。

對於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.
       });
}

您可能需要查看Unity.WebApi NuGet包,它將對所有這些進行排序,並且還可以滿足IDisposable組件的需要。

看到

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

要么

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

微軟已經為此創建了一個包。

從包管理器控制台運行以下命令。

安裝包Unity.AspNet.WebApi

如果您已經安裝了Unity,它將詢問您是否要覆蓋App_Start \\ UnityConfig.cs。 回答否並繼續。

無需更改任何其他代碼,DI(帶統一)將起作用。

我有同樣的錯誤,並在互聯網上尋找解決方案幾個小時。 最終看來我必須在調用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無法解決控制器中的依賴關系的問題

在最近的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魔術。 ;)

在閱讀完答案后,我仍然需要做很多工作才能找到這個問題,所以這里是為了同行的利益:這就是你需要在ASP.NET 4 Web API RC中做的所有事情(截至8月8日) '13):

  1. 添加對“Microsoft.Practices.Unity.dll”的引用[我在3.0.0.0版本上,通過NuGet添加]
  2. 添加對“Unity.WebApi.dll”的引用[我的版本為0.10.0.0,通過NuGet添加]
  3. 使用容器注冊類型映射 - 類似於Unity.WebApi項目中添加到項目中的Bootstrapper.cs中的代碼。
  4. 在從ApiController類繼承的控制器中,創建參數類型作為映射類型的參數化構造函數

瞧,您可以在沒有其他代碼行的情況下將依賴項注入構造函數中!

注意:我從其作者的博客中的一條評論中獲得了此信息。

由於使用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

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

我拋出了同樣的異常,在我的情況下,我在MVC3和MVC4二進制文件之間發生了沖突。 這阻止了我的控制器與我的IOC容器正確注冊。 檢查你的web.config並確保它指向正確版本的MVC。

使用Unity.WebAPI NuGet包時遇到了同樣的問題。 問題是該包從未在我的Global.asax中添加對UnityConfig.RegisterComponents()的調用。

Global.asax.cs應如下所示:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM