Heim >Backend-Entwicklung >C#.Net-Tutorial >Integration mit IoC/DI-Frameworks von Drittanbietern in ASP.NET Core-Anwendungen
In ASP.NET Core-Anwendungen kann die Integration von DI-Frameworks von Drittanbietern erreicht werden, indem ein ServiceProvider in der Methode „ConfigureServices“ zurückgegeben wird, die den Starttyp definiert. Aber so einfach ist das nicht. Lassen Sie es uns anhand eines Beispiels mitteilen
1. Der von der Methode „ConfigureServices“ zurückgegebene ServiceProvider ist nutzlos!
Wir können ein einfaches Beispiel verwenden um dieses Problem zu erklären. Wir definieren zunächst den folgenden MyServiceProvider, der eigentlich eine Kapselung eines anderen ServiceProviders ist. Der Einfachheit halber verwenden wir ein Wörterbuch, um die Zuordnungsbeziehung zwischen der Serviceschnittstelle und dem Implementierungstyp zu speichern. Diese Beziehung kann durch Aufrufen der Register-Methode registriert werden. Wenn in der GetService-Methode, die eine Dienstinstanz bereitstellt, der bereitgestellte Diensttyp registriert wurde, erstellen wir das entsprechende Instanzobjekt und geben es zurück. Andernfalls verwenden wir den gekapselten ServiceProvider, um Dienste bereitzustellen. Um sicherzustellen, dass die Dienstinstanz normal recycelt werden kann, fügen wir sie der Sammlung hinzu, die durch das Feld _disposables dargestellt wird, wenn der Diensttyp die IDisposable-Schnittstelle implementiert. Wenn die Dispose-Methode von MyServiceProvider aufgerufen wird, werden die Dispose-Methoden dieser bereitgestellten Dienstinstanzen aufgerufen.
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(); } }
Wir verwenden MyServiceProvider in einer ASP.NET Core-Anwendung wie folgt. Wie im folgenden Codeausschnitt lassen wir im registrierten Starup-Typ die Methode „ConfigureServices“ ein MyServiceProvider-Objekt zurückgeben. Die Zuordnung zwischen der Serviceschnittstelle IFoobar und dem Implementierungstyp Foobar wird in diesem MyServiceProvider-Objekt registriert. Bei der Verarbeitung der Anforderung verwenden wir das RequestServices-Attribut des aktuellen HttpContext-Objekts, um den ServiceProvider abzurufen, der Dienste für die Anforderungsverarbeitung bereitstellt, und versuchen, damit den registrierten IFoobar-Dienst abzurufen.
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 { }
Die gesamte Anwendung ist so einfach und es scheint kein Problem zu geben, aber wenn wir die Anwendung starten und den Browser verwenden, um auf die Anwendung zuzugreifen, passiert Folgendes Es erscheint ein Fehler. Die Fehlermeldung weist darauf hin, dass die Serviceschnittstelle IFoobar nicht registriert wurde.
2. Was ist der Grund?
Wir haben die Zuordnungsbeziehung zwischen IFoobar und Foobar im zurückgegebenen ServiceProvider eindeutig registriert. Warum sagt der von RequestServices zurückgegebene ServiceProvider, dass der Dienst noch nicht registriert wurde? Die einzige Erklärung besteht darin, dass der von der Methode „ConfigureServices“ zurückgegebene ServiceProvider und der von „RequestServices“ von HttpContext zurückgegebene ServiceProvider überhaupt nicht identisch sind. Tatsächlich handelt es sich nicht um dasselbe Objekt.
Der von der Methode „ConfigureServices“ zurückgegebene ServiceProvider wird als ServiceProvider von WebHost verwendet. Für jede empfangene Anfrage erstellt WebHost einen neuen ServiceProvider basierend auf diesem ServiceProvider als RequestServices-Attribut von HttpContext. Kinderverwaltung. Wenn der von RequestServices zurückgegebene ServiceProvider auf der Grundlage des von der Methode „ConfigureServices“ zurückgegebenen ServiceProviders erstellt wird, sollte er wie üblich auch in der Lage sein, den registrierten Diensttyp IFoobar zu identifizieren. Warum tritt der Fehler also immer noch auf?
Um dieses Problem zu verstehen, müssen Sie wissen, wie dieser sogenannte „untergeordnete ServiceProvider“ erstellt wird, der das Konzept von ServiceScope beinhaltet. Einfach ausgedrückt ist ServiceScope eine Kapselung eines ServiceProviders, und ersterer bestimmt den Lebenszyklus des letzteren. ServiceScope wird von ServiceScopeFactory erstellt, das als Dienst beim „übergeordneten ServiceProvider“ registriert ist. Wenn der „übergeordnete ServiceProvider“ einen „untergeordneten ServiceProvider“ erstellen muss, ruft er die GetService-Methode auf, um das ServiceScopeFactory-Objekt abzurufen (die verwendete Serviceschnittstelle ist IServiceScopeFactory) und verwendet diese zum Erstellen eines ServiceScope ist der zurückgegebene „untergeordnete ServiceProvider“.
Aber für unser MyServiceProvider-Objekt wird, wenn seine GetService-Methode aufgerufen wird, um zu versuchen, das ServiceScopeFactory-Objekt abzurufen, tatsächlich die ServiceScopeFactory erhalten, die dem gekapselten SerivceProvider zugeordnet ist. Daher ist es natürlich, einen „untergeordneten ServiceProvider“ zu erstellen. ” hat auch nichts mit MyServiceProvider zu tun.
3. Wie kann dieses Problem gelöst werden?
Da wir nun die Ursache des Problems kennen, haben wir eine Lösung. Die Lösung ist nicht kompliziert, wir benötigen lediglich die GetService-Methode von MyServiceProvider, um die ServiceScopeFactory zurückzugeben, die ihre eigene Dienstregistrierung widerspiegelt. Zu diesem Zweck definieren wir den folgenden ServiceScope und die entsprechende 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); } }
Zusätzlich haben wir einen Konstruktor für MyServiceProvider hinzugefügt, und die GetService-Methode hat auch entsprechenden Code für IServiceScopeFactory hinzugefügt.
public class MyServiceProvider : IServiceProvider, IDisposable { public MyServiceProvider(IServiceProvider innerServiceProvider, Dictionary<Type, Type> services) { _innerServiceProvider = innerServiceProvider; _services = services; _disposables = new List<IDisposable>(); } public object GetService(Type serviceType) { if (serviceType == typeof(IServiceScopeFactory)) { IServiceScopeFactory innerServiceScopeFactory = _innerServiceProvider.GetRequiredService<IServiceScopeFactory>(); return new ServiceScopeFactory(innerServiceScopeFactory, _services); } ... } ... }
Ich hoffe, dass das obige Teilen Freunden hilft, die solche Probleme lösen müssen!
Das obige ist der detaillierte Inhalt vonIntegration mit IoC/DI-Frameworks von Drittanbietern in ASP.NET Core-Anwendungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!