it-swarm.com.de

Instanzen mit ASP.NET Core DI lösen

Wie löse ich einen Typ mithilfe des in ASP.NET Core MVC integrierten Frameworks für die Abhängigkeitsinjektion manuell auf?

Das Aufstellen des Containers ist einfach genug:

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddTransient<ISomeService, SomeConcreteService>();
}

Aber wie kann ich ISomeService lösen, ohne eine Injektion durchzuführen? Zum Beispiel möchte ich dies tun:

ISomeService service = services.Resolve<ISomeService>();

Es gibt keine solchen Methoden in IServiceCollection.

213
Dave New

Die Schnittstelle IServiceCollection wird zum Erstellen eines Abhängigkeitsinjektionscontainers verwendet. Nachdem es vollständig erstellt wurde, wird es zu einer IServiceProvider -Instanz zusammengesetzt, die Sie zum Auflösen von Diensten verwenden können. Sie können eine IServiceProvider in jede Klasse injizieren. Die Klassen IApplicationBuilder und HttpContext können den Dienstanbieter auch über die Eigenschaften ApplicationServices bzw. RequestServices bereitstellen.

IServiceProvider definiert eine GetService(Type type) Methode zum Auflösen eines Dienstes:

_var service = (IFooService)serviceProvider.GetService(typeof(IFooService));
_

Es stehen auch verschiedene Methoden zur Erweiterung des Komforts zur Verfügung, z. B. serviceProvider.GetService<IFooService>() (using für _Microsoft.Extensions.DependencyInjection_ hinzufügen).

Auflösen von Diensten innerhalb der Startklasse

Abhängigkeiten injizieren

Die Laufzeitumgebung kann Dienste in den Konstruktor der Klasse Startup einfügen, z. B. IHostingEnvironment, IConfiguration und IServiceProvider. Beachten Sie, dass dieser Dienstanbieter eine Instanz ist, die von der Hosting-Schicht erstellt wurde und nur die Dienste zum Starten einer Anwendung enthält.

Services können auch mit der Methode Configure() injiziert werden. Sie können nach dem Parameter IApplicationBuilder eine beliebige Liste von Parametern hinzufügen. Sie können hier auch Ihre eigenen Dienste einfügen, die in der Methode ConfigureServices() registriert sind. Sie werden vom Anwendungsdienstanbieter und nicht vom aufgelöst ) Hosting Dienstleister.

_public void Configure(IApplicationBuilder app, IFooService fooService)
{
   // ...
}
_

Die Methode ConfigureServices() erlaubt jedoch kein Injizieren von Diensten, sondern akzeptiert nur ein Argument IServiceCollection. Dies ist die Methode, mit der Sie den Injektionscontainer für Anwendungsabhängigkeiten konfigurieren. Hier können Sie Dienste verwenden, die im Konstruktor des Startups eingefügt wurden. Zum Beispiel:

_public Startup(IConfiguration configuration)
{
    Configuration = configuration;
}

public IConfiguration Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    // Use Configuration here
}
_

Abhängigkeiten manuell auflösen

Wenn Sie Dienste manuell auflösen möchten, können Sie die Laufzeit eine IServiceProvider -Instanz in den Konstruktor einfügen lassen oder die ApplicationServices verwenden, die von IApplicationBuilder in der Configure() -Methode bereitgestellt wird:

_public Startup(IServiceProvider serviceProvider)
{
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}
_

oder

_public void Configure(IApplicationBuilder app)
{
    var serviceProvider = app.ApplicationServices;
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>();
}
_

Wenn Sie jedoch Dienste in der Methode ConfigureServices() auflösen müssen, benötigen Sie einen anderen Ansatz. Sie können ein Zwischenprodukt IServiceProvider aus einer IServiceCollection -Instanz erstellen, die die bis dahin registrierten Dienste enthält:

_public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IFooService, FooService>();

    // Build the intermediate service provider
    var sp = services.BuildServiceProvider();
    var fooService = sp.GetService<IFooService>();
}
_

Sie benötigen dazu das Paket Microsoft.Extensions.DependencyInjection .

Bitte beachten Sie:
Im Allgemeinen sollten Sie Dienste nicht innerhalb der ConfigureServices() -Methode auflösen, da dies tatsächlich der Ort ist, an dem Sie die Anwendungsdienste konfigurieren . Manchmal benötigen Sie nur Zugriff auf eine _IOptions<MyOptions>_ -Instanz. Sie können dies erreichen, indem Sie die Werte aus der Instanz IConfiguration an eine Instanz von MyOptions binden (was im Wesentlichen im Options-Framework der Fall ist):

_public void ConfigureServices(IServiceCollection services)
{
    var myOptions = new MyOptions();
    Configuration.GetSection("SomeSection").Bind(myOptions);
}
_

Das manuelle Auflösen von Diensten (auch bekannt als Service Locator) ist im Allgemeinen als Antimuster bezeichnet . Obwohl es seine Anwendungsfälle hat (für Frameworks und/oder Infrastrukturebenen), sollten Sie es so weit wie möglich vermeiden.

355
Henk Mollema

Das manuelle Auflösen von Instanzen erfordert die Verwendung der Schnittstelle IServiceProvider :

Auflösen von Abhängigkeiten in Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IMyService, MyService>();

    var serviceProvider = services.BuildServiceProvider();
    var service = serviceProvider.GetService<IMyService>();
}

Auflösen von Abhängigkeiten in Startup.Configure

public void Configure(
    IApplicationBuilder application,
    IServiceProvider serviceProvider)
{
    // By type.
    var service1 = (MyService)serviceProvider.GetService(typeof(MyService));

    // Using extension method.
    var service2 = serviceProvider.GetService<MyService>();

    // ...
}

Verwenden von Runtime Injected Services

Einige Typen können als Methodenparameter injiziert werden:

public class Startup
{
    public Startup(
        IHostingEnvironment hostingEnvironment,
        ILoggerFactory loggerFactory)
    {
    }

    public void ConfigureServices(
        IServiceCollection services)
    {
    }

    public void Configure(
        IApplicationBuilder application,
        IHostingEnvironment hostingEnvironment,
        IServiceProvider serviceProvider,
        ILoggerFactory loggerfactory,
        IApplicationLifetime applicationLifetime)
    {
    }
}

Auflösen von Abhängigkeiten in Controller-Aktionen

[HttpGet("/some-action")]
public string SomeAction([FromServices] IMyService myService) => "Hello";
75

Wenn Sie eine Anwendung mit einer Vorlage generieren, haben Sie so etwas in der Klasse Startup:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddMvc();
}

Dort können Sie dann Abhängigkeiten hinzufügen, zum Beispiel:

services.AddTransient<ITestService, TestService>();

Wenn Sie auf ITestService auf Ihrem Controller zugreifen möchten, können Sie IServiceProvider auf dem Konstruktor hinzufügen und es wird injiziert:

public HomeController(IServiceProvider serviceProvider)

Dann können Sie den hinzugefügten Dienst auflösen:

var service = serviceProvider.GetService<ITestService>();

Beachten Sie, dass Sie zur Verwendung der generischen Version den Namespace mit den Erweiterungen einschließen müssen:

using Microsoft.Extensions.DependencyInjection;

ITestService.cs

public interface ITestService
{
    int GenerateRandom();
}

TestService.cs

public class TestService : ITestService
{
    public int GenerateRandom()
    {
        return 4;
    }
}

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services)
{
    services.AddApplicationInsightsTelemetry(Configuration);
    services.AddMvc();

    services.AddTransient<ITestService, TestService>();
}

HomeController.cs

using Microsoft.Extensions.DependencyInjection;

namespace Core.Controllers
{
    public class HomeController : Controller
    {
        public HomeController(IServiceProvider serviceProvider)
        {
            var service = serviceProvider.GetService<ITestService>();
            int rnd = service.GenerateRandom();
        }
13
BrunoLM

Wenn Sie nur eine Abhängigkeit auflösen müssen, um sie an den Konstruktor einer anderen Abhängigkeit zu übergeben, die Sie registrieren, können Sie dies tun.

Angenommen, Sie hatten einen Service, der eine Zeichenfolge und einen ISomeService aufgenommen hat.

public class AnotherService : IAnotherService
{
    public AnotherService(ISomeService someService, string serviceUrl)
    {
        ...
    }
}

Wenn Sie dies in Startup.cs registrieren, müssen Sie dies tun:

services.AddScoped<IAnotherService>(ctx => 
      new AnotherService(ctx.GetService<ISomeService>(), "https://someservice.com/")
);
2
raterus

Auf diese Weise können Sie Abhängigkeiten in Attribute wie AuthorizeAttribute einfügen

var someservice = (ISomeService)context.HttpContext.RequestServices.GetService(typeof(ISomeService));
1
Bora Aydın