Program Tip

Unity를 사용하여 ASP.NET Web API 컨트롤러에 종속성을 삽입 할 수 없음

programtip 2020. 10. 5. 20:39
반응형

Unity를 사용하여 ASP.NET Web API 컨트롤러에 종속성을 삽입 할 수 없음


ASP.NET WebAPI 컨트롤러에 종속성을 주입하기 위해 IoC 컨테이너를 사용하여 성공한 사람이 있습니까? 나는 그것을 작동시킬 수없는 것 같다.

이것이 제가 지금하고있는 일입니다.

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, 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 cancelToken) at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync (HttpRequestMessage request, CancellationToken cancelToken)

컨트롤러는 다음과 같습니다.

public class ShoppingListController : System.Web.Http.ApiController
    {
        private Repositories.IProductListRepository _ProductListRepository;


        public ShoppingListController(Repositories.IUserRepository userRepository,
            Repositories.IProductListRepository productListRepository)
        {
            _ProductListRepository = productListRepository;
        }
}

내 Unity 파일은 다음과 같습니다.

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

해당 컨트롤러 활성화기를 Unity 컨테이너 자체의 구현으로 등록했습니다.

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

여기에 올바르게 작동하는 더 나은 솔루션이 있습니다.

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver


이 모든 것을 분류하고 IDisposable 구성 요소를 제공하는 Unity.WebApi NuGet 패키지를 살펴볼 수 있습니다.

보다

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

또는

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


Microsoft는이를위한 패키지를 만들었습니다.

패키지 관리자 콘솔에서 다음 명령을 실행하십시오.

설치 패키지 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 메서드가 없음을 발견했습니다. 컨트롤러와 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;
    }
}

또한 IoC 마술을 위해 UnityConfiguration (NuGet에서도 제공)을 사용합니다. ;)


답변을 읽은 후에도 여전히이 문제를 해결하기 위해 많은 작업을 수행해야했기 때문에 동료의 이익을 위해 여기에 있습니다. ASP.NET 4 Web API RC에서 수행해야하는 모든 작업입니다 (8 월 8 일 기준). '13) :

  1. "Microsoft.Practices.Unity.dll"에 대한 참조 추가 [NuGet을 통해 추가 된 버전 3.0.0.0에 있습니다.]
  2. "Unity.WebApi.dll"에 대한 참조 추가 [NuGet을 통해 추가 된 버전 0.10.0.0에 있습니다.]
  3. Unity.WebApi 프로젝트에서 프로젝트에 추가 한 Bootstrapper.cs의 코드와 유사하게 컨테이너에 유형 매핑을 등록합니다.
  4. ApiController 클래스에서 상속하는 컨트롤러에서 매개 변수 유형을 매핑 된 유형으로 갖는 매개 변수화 된 생성자를 만듭니다.

자, 보라, 다른 코드 줄없이 생성자에 의존성을 주입 할 수 있습니다!

참고 : 블로그의 작성자가 작성한 댓글 중 하나에서이 정보를 얻었습니다 .


동일한 예외가 발생했으며 제 경우에는 MVC3와 MVC4 바이너리간에 충돌이있었습니다. 이로 인해 컨트롤러가 IOC 컨테이너에 제대로 등록되지 않았습니다. web.config를 확인하고 올바른 버전의 MVC를 가리키고 있는지 확인하십시오.


이 문제는 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에 대한 간략한 요약입니다.

UnityNuGet에서 설치합니다 .

Create a new class called 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();
    }
}

Create a new class called UnityConfig:

public static class UnityConfig
{
    public static void ConfigureUnity(HttpConfiguration config)
    {
        var container = new UnityContainer();
        container.RegisterType<ISomethingRepository, SomethingRepository>();
        config.DependencyResolver = new UnityResolver(container);
    }
}

Edit App_Start -> WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    UnityConfig.ConfigureUnity(config);
    ...

Now it will work.

Original source but a bit modified: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection


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.

Global.asax.cs should look like this:

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

참고URL : https://stackoverflow.com/questions/9527988/cannot-inject-dependencies-into-asp-net-web-api-controller-using-unity

반응형