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.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);
}
}
해당 컨트롤러 활성화기를 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) :
- "Microsoft.Practices.Unity.dll"에 대한 참조 추가 [NuGet을 통해 추가 된 버전 3.0.0.0에 있습니다.]
- "Unity.WebApi.dll"에 대한 참조 추가 [NuGet을 통해 추가 된 버전 0.10.0.0에 있습니다.]
- Unity.WebApi 프로젝트에서 프로젝트에 추가 한 Bootstrapper.cs의 코드와 유사하게 컨테이너에 유형 매핑을 등록합니다.
- 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에 대한 간략한 요약입니다.
Unity
NuGet에서 설치합니다 .
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();
...
}
}
'Program Tip' 카테고리의 다른 글
Linux 커널 코드에서 __init는 무엇을 의미합니까? (0) | 2020.10.05 |
---|---|
기본 제공 WPF IValueConverters (0) | 2020.10.05 |
System.currentTimeMillis ()는 UTC 시간을 반환합니까? (0) | 2020.10.05 |
C ++에서 생성자 및 = 연산자 오버로드 복사 : 공통 함수가 가능합니까? (0) | 2020.10.05 |
P 요소 안에 중첩 될 수있는 HTML5 요소 목록? (0) | 2020.10.05 |