ASP.NET Core 애플리케이션에서는 시작 유형을 정의하는 ConfigureServices 메서드에서 ServiceProvider를 반환하여 타사 DI 프레임워크를 통합할 수 있습니다. 하지만 예제를 통해 공유해 보겠습니다.
1. ConfigureServices 메서드에서 반환된 ServiceProvider는 쓸모가 없습니다!
이 문제를 설명하는 간단한 예입니다. 먼저 실제로 다른 ServiceProvider를 캡슐화한 다음 MyServiceProvider를 정의했습니다. 단순화를 위해 사전을 사용하여 서비스 인터페이스와 구현 유형 간의 매핑 관계를 저장합니다. 이 관계는 Register 메서드를 호출하여 등록할 수 있습니다. 서비스 인스턴스를 제공하는 GetService 메소드에서 제공되는 서비스 유형이 등록되어 있으면 해당 인스턴스 객체를 생성하여 반환하고, 그렇지 않으면 캡슐화된 ServiceProvider를 사용하여 서비스를 제공합니다. 서비스 인스턴스가 정상적으로 재활용될 수 있도록 하기 위해 서비스 유형이 IDisposable 인터페이스를 구현하는 경우 이를 _disposables 필드가 나타내는 컬렉션에 추가합니다. MyServiceProvider의 Dispose 메서드가 호출되면 제공된 서비스 인스턴스의 Dispose 메서드가 호출됩니다.
public class MyServiceProvider : IServiceProvider, IDisposable { private IServiceProvider _innerServiceProvider; private Dictionary<Type, Type> _services; private List<IDisposable> _disposables; public MyServiceProvider(IServiceProvider innerServiceProvider) { _innerServiceProvider = innerServiceProvider; this._services = new Dictionary<Type, Type>(); _disposables = new List<IDisposable>(); } public MyServiceProvider Register<TFrom, TTo>() where TTo: TFrom, new() { _services[typeof(TFrom)] = typeof(TTo); return this; } public object GetService(Type serviceType) { Type implementation; if (_services.TryGetValue(serviceType, out implementation)) { object service = Activator.CreateInstance(implementation); IDisposable disposbale = service as IDisposable; if (null != disposbale) { _disposables.Add(disposbale); } return service; } return _innerServiceProvider.GetService(serviceType); } public void Dispose() { (_innerServiceProvider as IDisposable)?.Dispose(); foreach (var it in _disposables) { it.Dispose(); } _disposables.Clear(); } }
ASP.NET Core 애플리케이션에서는 다음과 같이 MyServiceProvider를 사용합니다. 다음 코드 조각과 같이 등록된 Starup 유형에서 ConfigureServices 메서드가 MyServiceProvider 개체를 반환하도록 합니다. 서비스 인터페이스 IFoobar와 구현 유형 Foobar 간의 매핑은 이 MyServiceProvider 객체에 등록됩니다. 요청을 처리할 때 현재 HttpContext 객체의 RequestServices 속성을 사용하여 요청 처리를 위한 서비스를 제공하는 ServiceProvider를 가져오고, 이를 사용하여 등록된 IFoobar 서비스를 가져오려고 합니다.
public class Program { public static void Main(string[] args) { new WebHostBuilder() .UseKestrel() .UseStartup<Startup>() .Build() .Run(); } } public class Startup { public IServiceProvider ConfigureServices(IServiceCollection services) { return new MyServiceProvider(services.BuildServiceProvider()) .Register<IFoobar, Foobar>(); } public void Configure(IApplicationBuilder app) { app.UseDeveloperExceptionPage() .Run(async context => await context.Response.WriteAsync(context.RequestServices.GetRequiredService<IFoobar>().GetType().Name)); } } public interface IFoobar { } public class Foobar : IFoobar { }
애플리케이션 전체가 너무 간단해서 문제 없어 보이지만, 애플리케이션을 시작하고 브라우저를 사용하여 애플리케이션에 액세스하면 다음과 같은 오류가 발생합니다. 나타나다. 오류 메시지는 IFoobar 서비스 인터페이스가 등록되지 않았음을 나타냅니다.
2. 이유가 무엇인가요?
반환된 ServiceProvider에 IFoobar와 Foobar 간의 매핑 관계를 명확하게 등록했습니다. RequestServices에서 반환한 ServiceProvider에 서비스가 아직 등록되지 않았다고 표시되는 이유는 무엇인가요? 유일한 설명은 ConfigureServices 메서드에서 반환된 ServiceProvider와 HttpContext의 RequestServices에서 반환된 ServiceProvider가 전혀 동일하지 않다는 것입니다. 사실, 그것들은 동일한 객체가 아닙니다.
ConfigureServices 메소드에서 반환된 ServiceProvider는 수신된 각 요청에 대해 WebHost는 HttpContext의 RequestServices 속성으로 이 ServiceProvider를 기반으로 새 ServiceProvider를 생성합니다. 자녀 관리. 평소와 같이 RequestServices에서 반환된 ServiceProvider가 ConfigureServices 메서드에서 반환된 ServiceProvider를 기반으로 생성된 경우 등록된 서비스 유형 IFoobar도 식별할 수 있어야 하는데 오류가 계속 발생하는 이유는 무엇입니까?
이 문제를 이해하려면 ServiceScope 개념을 포함하는 소위 "하위 ServiceProvider"가 어떻게 생성되는지 알아야 합니다. 간단히 말해서 ServiceScope는 ServiceProvider를 캡슐화한 것이며 전자가 후자의 수명 주기를 결정합니다. ServiceScope는 "상위 ServiceProvider"에 서비스로 등록된 ServiceScopeFactory에 의해 생성됩니다. "상위 ServiceProvider"가 "하위 ServiceProvider"를 생성해야 하는 경우 GetService 메서드를 호출하여 ServiceScopeFactory 개체(사용된 서비스 인터페이스는 IServiceScopeFactory)를 가져오고 후자를 사용하여 이 ServiceScope에서 제공하는 ServiceProvider를 생성합니다. 반환된 "하위 ServiceProvider"입니다.
그러나 MyServiceProvider 개체의 경우 GetService 메서드를 호출하여 ServiceScopeFactory 개체를 얻으려고 하면 실제로 얻은 것은 캡슐화된 SerivceProvider와 연결된 ServiceScopeFactory이므로 "하위 ServiceProvider"를 만드는 것이 당연합니다. ” 또한 MyServiceProvider와 아무 관련이 없습니다.
3. 이 문제를 어떻게 해결하나요?
이제 문제의 원인을 알았으니 해결책도 있습니다. 솔루션은 복잡하지 않습니다. 자체 서비스 등록을 반영하는 ServiceScopeFactory를 반환하려면 MyServiceProvider의 GetService 메서드만 필요합니다. 이를 위해 다음 ServiceScope 및 해당 ServiceScopeFactory를 정의합니다.
internal class ServiceScope : IServiceScope { private MyServiceProvider _serviceProvider; public ServiceScope(IServiceScope innserServiceScope, Dictionary<Type, Type> services) { _serviceProvider = new MyServiceProvider(innserServiceScope.ServiceProvider, services); } public IServiceProvider ServiceProvider { get { return _serviceProvider; } } public void Dispose() { _serviceProvider.Dispose(); } } internal class ServiceScopeFactory : IServiceScopeFactory { private IServiceScopeFactory _innerServiceFactory; private Dictionary<Type, Type> _services; public ServiceScopeFactory(IServiceScopeFactory innerServiceFactory, Dictionary<Type, Type> services) { _innerServiceFactory = innerServiceFactory; _services = services; } public IServiceScope CreateScope() { return new ServiceScope(_innerServiceFactory.CreateScope(), _services); } }
또한 MyServiceProvider에 대한 생성자를 추가했으며 GetService 메서드에는 IServiceScopeFactory에 대한 해당 코드도 추가했습니다.
위 공유 내용이 이러한 문제를 해결해야 하는 친구들에게 도움이 되기를 바랍니다!
위 내용은 ASP.NET Core 애플리케이션에서 타사 IoC/DI 프레임워크와 통합의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!