Dependency Injection in ASP.NET CoreDependency injection in ASP.NET Core

Von Kirk Larkin, Steve Smith, Scott Addie und Brandon DahlerBy Kirk Larkin, Steve Smith, Scott Addie, and Brandon Dahler

ASP.NET Core unterstützt das Softwareentwurfsmuster Abhängigkeitsinjektion. Damit kann eine Umkehrung der Steuerung (Inversion of Control, IoC) zwischen Klassen und ihren Abhängigkeiten erreicht werden.ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.

Weitere Informationen zur Abhängigkeitsinjektion innerhalb von MVC-Controllern finden Sie unter Dependency Injection in Controller in ASP.NET Core.For more information specific to dependency injection within MVC controllers, see Dependency Injection in Controller in ASP.NET Core.

Informationen zum Verwenden der Abhängigkeitsinjektion in anderen Apps als Web-Apps finden Sie unter Abhängigkeitsinjektion in .NET.For information on using dependency injection in applications other than web apps, see Dependency injection in .NET.

Weitere Informationen zur Dependency Injection für Optionen finden Sie unter Optionsmuster in ASP.NET Core.For more information on dependency injection of options, see Optionsmuster in ASP.NET Core.

Dieses Thema enthält Informationen zur Dependency Injection in ASP.NET Core.This topic provides information on dependency injection in ASP.NET Core. Die primäre Dokumentation zur Verwendung der Abhängigkeitsinjektion ist in Abhängigkeitsinjektion in .NET enthalten.The primary documentation on using dependency injection is contained in Dependency injection in .NET.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)View or download sample code (how to download)

Übersicht über AbhängigkeitsinjektionOverview of dependency injection

Eine Abhängigkeit ist ein Objekt, von dem ein anderes Objekt abhängig ist.A dependency is an object that another object depends on. Überprüfen Sie die folgende MyDependency-Klasse mit einer WriteMessage-Methode, von der andere Klassen abhängig sind:Examine the following MyDependency class with a WriteMessage method that other classes depend on:

public class MyDependency
{
    public void WriteMessage(string message)
    {
        Console.WriteLine($"MyDependency.WriteMessage called. Message: {message}");
    }
}

Eine Klasse kann eine Instanz der MyDependency-Klasse erstellen, um die WriteMessage-Methode zu nutzen.A class can create an instance of the MyDependency class to make use of its WriteMessage method. Im folgenden Beispiel ist die MyDependency-Klasse eine Abhängigkeit der IndexModel-Klasse:In the following example, the MyDependency class is a dependency of the IndexModel class:

public class IndexModel : PageModel
{
    private readonly MyDependency _dependency = new MyDependency();

    public void OnGet()
    {
        _dependency.WriteMessage("IndexModel.OnGet created this message.");
    }
}

Die Klasse erstellt die MyDependency-Klasse und weist eine direkte Abhängigkeit von dieser auf.The class creates and directly depends on the MyDependency class. Codeabhängigkeiten (wie im vorherigen Beispiel) sind problematisch und sollten aus folgenden Gründen vermieden werden:Code dependencies, such as in the previous example, are problematic and should be avoided for the following reasons:

  • Die IndexModel-Klasse muss geändert werden, um MyDependency durch eine andere Implementierung zu ersetzen.To replace MyDependency with a different implementation, the IndexModel class must be modified.
  • Wenn MyDependency über Abhängigkeiten verfügt, müssen diese ebenfalls von der IndexModel-Klasse konfiguriert werden.If MyDependency has dependencies, they must also be configured by the IndexModel class. In einem großen Projekt mit mehreren Klassen, die von MyDependency abhängig sind, wird der Konfigurationscode über die App verteilt.In a large project with multiple classes depending on MyDependency, the configuration code becomes scattered across the app.
  • Diese Implementierung ist nicht für Komponententests geeignet.This implementation is difficult to unit test. Die App sollte eine MyDependency-Modell- oder Stubklasse verwenden, was mit diesem Ansatz nicht möglich ist.The app should use a mock or stub MyDependency class, which isn't possible with this approach.

Die Abhängigkeitsinjektion löst dieses Problem mithilfe der folgenden Schritte:Dependency injection addresses these problems through:

  • Die Verwendung einer Schnittstelle oder Basisklasse zur Abstraktion der Abhängigkeitsimplementierung.The use of an interface or base class to abstract the dependency implementation.
  • Registrierung der Abhängigkeit in einem Dienstcontainer.Registration of the dependency in a service container. ASP.NET Core stellt einen integrierten Dienstcontainer (IServiceProvider) bereit.ASP.NET Core provides a built-in service container, IServiceProvider. Dienste werden üblicherweise in der Startup.ConfigureServices-Methode der App registriert.Services are typically registered in the app's Startup.ConfigureServices method.
  • Die Injektion des Diensts in den Konstruktor der Klasse, wo er verwendet wird.Injection of the service into the constructor of the class where it's used. Das Framework erstellt eine Instanz der Abhängigkeit und entfernt diese, wenn sie nicht mehr benötigt wird.The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

In der Beispiel-App definiert die IMyDependency-Schnittstelle die WriteMessage-Methode:In the sample app, the IMyDependency interface defines the WriteMessage method:

public interface IMyDependency
{
    void WriteMessage(string message);
}

Diese Schnittstelle wird durch einen konkreten Typ (MyDependency) implementiert:This interface is implemented by a concrete type, MyDependency:

public class MyDependency : IMyDependency
{
    public void WriteMessage(string message)
    {
        Console.WriteLine($"MyDependency.WriteMessage Message: {message}");
    }
}

Die Beispiel-App registriert den IMyDependency-Dienst mit dem konkreten Typ MyDependency.The sample app registers the IMyDependency service with the concrete type MyDependency. Die AddScoped-Methode registriert den Dienst mit der Lebensdauer einer einzelnen Anforderung.The AddScoped method registers the service with a scoped lifetime, the lifetime of a single request. Auf die Dienstlebensdauer wird später in diesem Artikel eingegangen.Service lifetimes are described later in this topic.

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyDependency, MyDependency>();

    services.AddRazorPages();
}

In der Beispiel-App wird der IMyDependency-Dienst angefordert und zum Aufrufen der WriteMessage-Methode verwendet:In the sample app, the IMyDependency service is requested and used to call the WriteMessage method:

public class Index2Model : PageModel
{
    private readonly IMyDependency _myDependency;

    public Index2Model(IMyDependency myDependency)
    {
        _myDependency = myDependency;            
    }

    public void OnGet()
    {
        _myDependency.WriteMessage("Index2Model.OnGet");
    }
}

Bei Verwendung des Dependency-Injection-Musters geht der Controller wie folgt vor:By using the DI pattern, the controller:

  • Er verwendet nicht den konkreten Typ MyDependency, nur die von diesem implementierte IMyDependency-Schnittstelle.Doesn't use the concrete type MyDependency, only the IMyDependency interface it implements. Dadurch kann die vom Controller verwendete Implementierung einfacher geändert werden, ohne den Controller selbst zu bearbeiten.That makes it easy to change the implementation that the controller uses without modifying the controller.
  • Er erstellt keine Instanz von MyDependency. Diese wird vom DI-Container erstellt.Doesn't create an instance of MyDependency, it's created by the DI container.

Die Implementierung der IMyDependency-Schnittstelle kann mithilfe der integrierten Protokollierungs-API verbessert werden:The implementation of the IMyDependency interface can be improved by using the built-in logging API:

public class MyDependency2 : IMyDependency
{
    private readonly ILogger<MyDependency2> _logger;

    public MyDependency2(ILogger<MyDependency2> logger)
    {
        _logger = logger;
    }

    public void WriteMessage(string message)
    {
        _logger.LogInformation( $"MyDependency2.WriteMessage Message: {message}");
    }
}

Die aktualisierte ConfigureServices-Methode registriert die neue IMyDependency-Implementierung:The updated ConfigureServices method registers the new IMyDependency implementation:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IMyDependency, MyDependency2>();

    services.AddRazorPages();
}

MyDependency2 hängt von der ILogger<TCategoryName>-Schnittstelle ab, die im Konstruktor angefordert wird.MyDependency2 depends on ILogger<TCategoryName>, which it requests in the constructor. ILogger<TCategoryName> ist ein vom Framework bereitgestellter Dienst.ILogger<TCategoryName> is a framework-provided service.

Die Abhängigkeitsinjektion wird häufig als Verkettung verwendet.It's not unusual to use dependency injection in a chained fashion. Jede angeforderte Abhängigkeit fordert wiederum ihre eigenen Abhängigkeiten an.Each requested dependency in turn requests its own dependencies. Der Container löst die Abhängigkeiten im Diagramm auf und gibt den vollständig aufgelösten Dienst zurück.The container resolves the dependencies in the graph and returns the fully resolved service. Die gesammelten aufzulösenden Abhängigkeiten werden als Abhängigkeitsstruktur, Abhängigkeitsdiagramm oder Objektdiagramm bezeichnet.The collective set of dependencies that must be resolved is typically referred to as a dependency tree, dependency graph, or object graph.

Der Container löst ILogger<TCategoryName> unter Verwendung der (generischen) offenen Typen auf, wodurch nicht mehr jeder (generische) konstruierte Typ registriert werden muss:The container resolves ILogger<TCategoryName> by taking advantage of (generic) open types, eliminating the need to register every (generic) constructed type.

Im Dependency-Injection-Kontext ist ein Dienst:In dependency injection terminology, a service:

  • in der Regel ein Objekt, das einen Dienst für andere Objekte bereitstellt, z. B. den IMyDependency-Dienst.Is typically an object that provides a service to other objects, such as the IMyDependency service.
  • kein Webdienst, obwohl ein Dienst einen Webdienst verwenden kannIs not related to a web service, although the service may use a web service.

Das Framework bietet eine stabiles Protokollierungssystem.The framework provides a robust logging system. Die in den vorherigen Beispielen veranschaulichten IMyDependency-Implementierungen wurden geschrieben, um die grundlegende Dependency Injection zu demonstrieren, nicht zum Implementieren der Protokollierung.The IMyDependency implementations shown in the preceding examples were written to demonstrate basic DI, not to implement logging. Die meisten Apps müssen keine Protokollierungen schreiben.Most apps shouldn't need to write loggers. Der folgende Code veranschaulicht die Verwendung der Standardprotokollierung, bei der keine Dienste in ConfigureServices registriert werden müssen:The following code demonstrates using the default logging, which doesn't require any services to be registered in ConfigureServices:

public class AboutModel : PageModel
{
    private readonly ILogger _logger;

    public AboutModel(ILogger<AboutModel> logger)
    {
        _logger = logger;
    }
    
    public string Message { get; set; }

    public void OnGet()
    {
        Message = $"About page visited at {DateTime.UtcNow.ToLongTimeString()}";
        _logger.LogInformation(Message);
    }
}

Bei Verwendung des vorangehenden Codes muss ConfigureServices nicht aktualisiert werden, weil die Protokollierung vom Framework bereitgestellt wird.Using the preceding code, there is no need to update ConfigureServices, because logging is provided by the framework.

In den Start eingefügte DiensteServices injected into Startup

Dienste können in den Startup-Konstruktor und die Startup.Configure-Methode eingefügt werden.Services can be injected into the Startup constructor and the Startup.Configure method.

Nur die folgenden Dienste können in den Startup-Konstruktor eingefügt werden, wenn der generische Host (IHostBuilder) verwendet wird:Only the following services can be injected into the Startup constructor when using the Generic Host (IHostBuilder):

Jeder Dienst, der mit dem DI-Container registriert wurde, kann in die Startup.Configure-Methode eingefügt werden:Any service registered with the DI container can be injected into the Startup.Configure method:

public void Configure(IApplicationBuilder app, ILogger<Startup> logger)
{
    ...
}

Weitere Informationen finden Sie unter Anwendungsstart in ASP.NET Core und unter Zugriffskonfiguration beim Start.For more information, see Anwendungsstart in ASP.NET Core and Access configuration in Startup.

Registrieren von Dienstgruppen mit ErweiterungsmethodenRegister groups of services with extension methods

Das ASP.NET Core-Framework verwendet eine Konvention zum Registrieren einer Gruppe verwandter Dienste.The ASP.NET Core framework uses a convention for registering a group of related services. Die Konvention besteht darin, eine einzelne Add{GROUP_NAME}-Erweiterungsmethode zum Registrieren aller Dienste zu verwenden, die von einem Frameworkfeature benötigt werden.The convention is to use a single Add{GROUP_NAME} extension method to register all of the services required by a framework feature. Beispielsweise registriert die AddControllers-Erweiterungsmethode die für MVC-Controller erforderlichen Dienste.For example, the AddControllers extension method registers the services required for MVC controllers.

Der folgende Code wird von der Razor Pages-Vorlage auf Grundlage einzelner Benutzerkonten generiert. Er veranschaulicht, wie mit den Erweiterungsmethoden AddDbContext und AddDefaultIdentity zusätzliche Dienste zum Container hinzugefügt werden können:The following code is generated by the Razor Pages template using individual user accounts and shows how to add additional services to the container using the extension methods AddDbContext and AddDefaultIdentity:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();
}

Mit der folgenden ConfigureServices-Methode können Sie Dienste registrieren und Optionen konfigurieren:Consider the following ConfigureServices method, which registers services and configures options:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<PositionOptions>(
        Configuration.GetSection(PositionOptions.Position));
    services.Configure<ColorOptions>(
        Configuration.GetSection(ColorOptions.Color));

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddScoped<IMyDependency2, MyDependency2>();

    services.AddRazorPages();
}

Ähnliche Registrierungsgruppen können in eine Erweiterungsmethode verschoben werden, um Dienste zu registrieren.Related groups of registrations can be moved to an extension method to register services. Die Konfigurationsdienste werden beispielsweise folgender Klasse hinzugefügt:For example, the configuration services are added to the following class:

using ConfigSample.Options;
using Microsoft.Extensions.Configuration;

namespace Microsoft.Extensions.DependencyInjection
{
    public static class MyConfigServiceCollectionExtensions
    {
        public static IServiceCollection AddConfig(
             this IServiceCollection services, IConfiguration config)
        {
            services.Configure<PositionOptions>(
                config.GetSection(PositionOptions.Position));
            services.Configure<ColorOptions>(
                config.GetSection(ColorOptions.Color));

            return services;
        }
    }
}

Die verbleibenden Dienste werden in einer ähnlichen Klasse registriert.The remaining services are registered in a similar class. Die folgende ConfigureServices-Methode verwendet die neuen Erweiterungsmethoden, um die Dienste zu registrieren:The following ConfigureServices method uses the new extension methods to register the services:

public void ConfigureServices(IServiceCollection services)
{
    services.AddConfig(Configuration)
            .AddMyDependencyGroup();

    services.AddRazorPages();
}

Hinweis: Jede services.Add{GROUP_NAME}-Erweiterungsmethode fügt Dienste hinzu und konfiguriert diese möglicherweise.Note: Each services.Add{GROUP_NAME} extension method adds and potentially configures services. Beispielsweise fügt AddControllersWithViews den MVC-Controller für Dienste mit den erforderlichen Ansichten hinzu, und AddRazorPages fügt die für Razor Pages benötigten Dienste hinzu.For example, AddControllersWithViews adds the services MVC controllers with views require, and AddRazorPages adds the services Razor Pages requires. Es wird empfohlen, dass Apps dieser Namenskonvention folgen.We recommended that apps follow this naming convention. Platzieren Sie Erweiterungsmethoden im Namespace Microsoft.Extensions.DependencyInjection, um Gruppen von Dienstregistrierungen zu kapseln.Place extension methods in the Microsoft.Extensions.DependencyInjection namespace to encapsulate groups of service registrations.

DienstlebensdauerService lifetimes

Weitere Informationen finden Sie unter Dienstlebensdauer in Abhängigkeitsinjektion in .NET.See Service lifetimes in Dependency injection in .NET

Zum Verwenden bereichsbezogener Dienste in Middleware, verwenden Sie einen der folgenden Ansätze:To use scoped services in middleware, use one of the following approaches:

  • Fügen Sie den Dienst in die Invoke- oder InvokeAsync-Methode der Middleware ein.Inject the service into the middleware's Invoke or InvokeAsync method. Bei Verwendung der Constructor Injection wird eine Runtimeausnahme ausgelöst, weil dem bereichsbezogenen Dienst das Verhalten eines Singletons aufgezwungen wird.Using constructor injection throws a runtime exception because it forces the scoped service to behave like a singleton. Im Beispiel des Abschnitts Lebensdauer und Registrierungsoptionen wird der InvokeAsync-Ansatz veranschaulicht.The sample in the Lifetime and registration options section demonstrates the InvokeAsync approach.
  • Verwenden Sie factorybezogene Middleware.Use Factory-based middleware. Middleware, die mit diesem Ansatz registriert wurde, wird pro Clientanforderung (Verbindung) aktiviert, wodurch bereichsbezogene Dienste in die InvokeAsync-Methode der Middleware eingefügt werden können.Middleware registered using this approach is activated per client request (connection), which allows scoped services to be injected into the middleware's InvokeAsync method.

Weitere Informationen finden Sie unter Schreiben von benutzerdefinierter ASP.NET Core-Middleware.For more information, see Schreiben von benutzerdefinierter ASP.NET Core-Middleware.

DienstregistrierungsmethodenService registration methods

Weitere Informationen finden Sie unter Dienstregistrierungsmethoden in Abhängigkeitsinjektion in .NET.See Service registration methods in Dependency injection in .NET

Es ist üblich, mehrere Implementierungen zu verwenden, wenn Typen zu Testzecken simuliert werden.It's common to use multiple implementations when mocking types for testing.

Das Registrieren eines Diensts mit nur einem Implementierungstyp entspricht dem Registrieren dieses Diensts mit demselben Implementierungs- und Diensttyp.Registering a service with only an implementation type is equivalent to registering that service with the same implementation and service type. Aus diesem Grund können nicht mehrere Implementierungen eines Diensts mithilfe von Methoden registriert werden, die keinen expliziten Diensttyp erwarten.This is why multiple implementations of a service cannot be registered using the methods that don't take an explicit service type. Solche Methoden können mehrere Instanzen eines Diensts registrieren, die dann jedoch alle denselben Implementierungstyp aufweisen.These methods can register multiple instances of a service, but they will all have the same implementation type.

Alle oben genannten Dienstregistrierungsmethoden können zum Registrieren mehrerer Dienstinstanzen desselben Diensttyps verwendet werden.Any of the above service registration methods can be used to register multiple service instances of the same service type. Im folgenden Beispiel wird AddSingleton zweimal mit IMyDependency als Diensttyp aufgerufen.In the following example, AddSingleton is called twice with IMyDependency as the service type. Mit dem zweiten Aufruf von AddSingleton wird der vorhandene Singleton überschrieben, wenn er als IMyDependency aufgelöst wurde. Wenn mehrere Dienste über IEnumerable<IMyDependency> aufgelöst werden, wird der neue Singleton hinzugefügt und der alte beibehalten.The second call to AddSingleton overrides the previous one when resolved as IMyDependency and adds to the previous one when multiple services are resolved via IEnumerable<IMyDependency>. Dienste werden beim Auflösen mit IEnumerable<{SERVICE}> in der Reihenfolge angezeigt, in der sie registriert wurden.Services appear in the order they were registered when resolved via IEnumerable<{SERVICE}>.

services.AddSingleton<IMyDependency, MyDependency>();
services.AddSingleton<IMyDependency, DifferentDependency>();

public class MyService
{
    public MyService(IMyDependency myDependency, 
       IEnumerable<IMyDependency> myDependencies)
    {
        Trace.Assert(myDependency is DifferentDependency);

        var dependencyArray = myDependencies.ToArray();
        Trace.Assert(dependencyArray[0] is MyDependency);
        Trace.Assert(dependencyArray[1] is DifferentDependency);
    }
}

Verhalten von Constructor InjectionConstructor injection behavior

Weitere Informationen finden Sie unter Konstruktorinjektionsverhalten in Abhängigkeitsinjektion in .NET.See Constructor injection behavior in Dependency injection in .NET

Entity Framework-KontexteEntity Framework contexts

Entity Framework-Kontexte werden einem Dienstcontainer standardmäßig mithilfe der bereichsbezogenen Lebensdauer hinzugefügt, da Datenbankvorgänge von Web-Apps normalerweise auf den Clientanforderungsbereich bezogen werden.By default, Entity Framework contexts are added to the service container using the scoped lifetime because web app database operations are normally scoped to the client request. Legen Sie die Lebensdauer mithilfe einer AddDbContext-Überladung fest, um eine andere Lebensdauer zu verwenden.To use a different lifetime, specify the lifetime by using an AddDbContext overload. Dienste einer festgelegten Lebensdauer sollten keinen Datenbankkontext mit einer Lebensdauer verwenden, die kürzer als die Lebensdauer des Diensts ist.Services of a given lifetime shouldn't use a database context with a lifetime that's shorter than the service's lifetime.

Lebensdauer und RegistrierungsoptionenLifetime and registration options

In den folgenden Schnittstellen, die einen Task als Vorgang mit einem Bezeichner (OperationId) darstellen, wird der Unterschied zwischen Dienstlebensdauern und ihren Registrierungsoptionen veranschaulicht.To demonstrate the difference between service lifetimes and their registration options, consider the following interfaces that represent a task as an operation with an identifier, OperationId. Je nachdem, wie die Dienstlebensdauer für die folgenden Schnittstellen konfiguriert ist, stellt der Container auf Anforderung einer Klasse entweder die gleiche oder eine andere Instanz des Diensts zur Verfügung:Depending on how the lifetime of an operation's service is configured for the following interfaces, the container provides either the same or different instances of the service when requested by a class:

public interface IOperation
{
    string OperationId { get; }
}

public interface IOperationTransient : IOperation { }
public interface IOperationScoped : IOperation { }
public interface IOperationSingleton : IOperation { }

Die folgende Operation-Klasse implementiert alle vorangehenden Schnittstellen.The following Operation class implements all of the preceding interfaces. Der Operation-Konstruktor generiert einen eindeutigen Bezeichner (GUID) und speichert die letzten 4 Zeichen in der OperationId-Eigenschaft:The Operation constructor generates a GUID and stores the last 4 characters in the OperationId property:

public class Operation : IOperationTransient, IOperationScoped, IOperationSingleton
{
    public Operation()
    {
        OperationId = Guid.NewGuid().ToString()[^4..];
    }

    public string OperationId { get; }
}

Die Startup.ConfigureServices-Methode erstellt mehrere Registrierungen der Operation-Klasse entsprechend der benannten Lebensdauern:The Startup.ConfigureServices method creates multiple registrations of the Operation class according to the named lifetimes:

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();

    services.AddRazorPages();
}

Die Beispiel-App veranschaulicht die Objektlebensdauer sowohl in als auch zwischen Anforderungen.The sample app demonstrates object lifetimes both within and between requests. IndexModel und die Middleware fordern jede Art von IOperation-Typ an und protokollieren OperationId für jeden Typ:The IndexModel and the middleware request each kind of IOperation type and log the OperationId for each:

public class IndexModel : PageModel
{
    private readonly ILogger _logger;
    private readonly IOperationTransient _transientOperation;
    private readonly IOperationSingleton _singletonOperation;
    private readonly IOperationScoped _scopedOperation;

    public IndexModel(ILogger<IndexModel> logger,
                      IOperationTransient transientOperation,
                      IOperationScoped scopedOperation,
                      IOperationSingleton singletonOperation)
    {
        _logger = logger;
        _transientOperation = transientOperation;
        _scopedOperation    = scopedOperation;
        _singletonOperation = singletonOperation;
    }

    public void  OnGet()
    {
        _logger.LogInformation("Transient: " + _transientOperation.OperationId);
        _logger.LogInformation("Scoped: "    + _scopedOperation.OperationId);
        _logger.LogInformation("Singleton: " + _singletonOperation.OperationId);
    }
}

Ähnlich wie IndexModel löst die Middleware dieselben Dienste auf:Similar to the IndexModel, the middleware resolves the same services:

public class MyMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    private readonly IOperationTransient _transientOperation;
    private readonly IOperationSingleton _singletonOperation;

    public MyMiddleware(RequestDelegate next, ILogger<MyMiddleware> logger,
        IOperationTransient transientOperation,
        IOperationSingleton singletonOperation)
    {
        _logger = logger;
        _transientOperation = transientOperation;
        _singletonOperation = singletonOperation;
        _next = next;
    }

    public async Task InvokeAsync(HttpContext context,
        IOperationScoped scopedOperation)
    {
        _logger.LogInformation("Transient: " + _transientOperation.OperationId);
        _logger.LogInformation("Scoped: "    + scopedOperation.OperationId);
        _logger.LogInformation("Singleton: " + _singletonOperation.OperationId);

        await _next(context);
    }
}

public static class MyMiddlewareExtensions
{
    public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyMiddleware>();
    }
}

Bereichsbezogene Dienste müssen in der InvokeAsync-Methode aufgelöst werden:Scoped services must be resolved in the InvokeAsync method:

public async Task InvokeAsync(HttpContext context,
    IOperationScoped scopedOperation)
{
    _logger.LogInformation("Transient: " + _transientOperation.OperationId);
    _logger.LogInformation("Scoped: "    + scopedOperation.OperationId);
    _logger.LogInformation("Singleton: " + _singletonOperation.OperationId);

    await _next(context);
}

Die Protokollierungsausgabe zeigt Folgendes an:The logger output shows:

  • Objekte vom Typ Vorübergehend sind immer unterschiedlich.Transient objects are always different. Der vorübergehende OperationId-Wert unterscheidet sich in IndexModel und der Middleware.The transient OperationId value is different in the IndexModel and in the middleware.
  • Bereichsbezogene Objekte sind für jede Anforderung identisch, aber unterscheiden sich für jede Anforderung.Scoped objects are the same for each request but different across each request.
  • Singletonobjekte sind für jede Anforderung identisch.Singleton objects are the same for every request.

Sie können "Logging:LogLevel:Microsoft:Error" in der Datei appsettings.Development.json festlegen, um die Protokollierungsausgabe zu reduzieren:To reduce the logging output, set "Logging:LogLevel:Microsoft:Error" in the appsettings.Development.json file:

{
  "MyKey": "MyKey from appsettings.Developement.json",
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "System": "Debug",
      "Microsoft": "Error"
    }
  }
}

Abrufen von Diensten aus „Main“Call services from main

Erstellen Sie IServiceScope mit IServiceScopeFactory.CreateScope, um einen bereichsbezogenen Dienst innerhalb des Anwendungsbereichs aufzulösen.Create an IServiceScope with IServiceScopeFactory.CreateScope to resolve a scoped service within the app's scope. Dieser Ansatz eignet sich gut dafür, beim Start auf einen bereichsbezogenen Dienst zuzugreifen und Initialisierungsaufgaben auszuführen.This approach is useful to access a scoped service at startup to run initialization tasks.

Im folgenden Beispiel wird der Zugriff auf den bereichsbezogenen IMyDependency-Dienst und der Aufruf dessen WriteMessage-Methode in Program.Main veranschaulicht:The following example shows how to access the scoped IMyDependency service and call its WriteMessage method in Program.Main:

public class Program
{
    public static void Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var myDependency = services.GetRequiredService<IMyDependency>();
                myDependency.WriteMessage("Call services from main");
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred.");
            }
        }

        host.Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

BereichsvalidierungScope validation

Weitere Informationen finden Sie unter Konstruktorinjektionsverhalten in Abhängigkeitsinjektion in .NET.See Constructor injection behavior in Dependency injection in .NET

Weitere Informationen finden Sie unter Bereichsvalidierung.For more information, see Scope validation.

Anfordern von DienstenRequest Services

Die in einer ASP.NET Core-Anforderung verfügbaren Dienste werden über die Sammlung HttpContext.RequestServices zur Verfügung gestellt.The services available within an ASP.NET Core request are exposed through the HttpContext.RequestServices collection. Wenn Dienste innerhalb einer Anforderung angefordert werden, werden die Dienste und ihre Abhängigkeiten aus der RequestServices-Sammlung aufgelöst.When services are requested from inside of a request, the services and their dependencies are resolved from the RequestServices collection.

Das Framework erstellt einen Bereich pro Anforderung, und RequestServices stellt den bereichsbezogenen Dienstanbieter zur Verfügung.The framework creates a scope per request and RequestServices exposes the scoped service provider. Alle bereichsbezogenen Dienste sind gültig, solange die Anforderung aktiv ist.All scoped services are valid for as long as the request is active.

Hinweis

Sie sollten das Anfordern von Abhängigkeiten als Konstruktorparameter zum Auflösen von Diensten aus der RequestServices-Sammlung bevorzugen.Prefer requesting dependencies as constructor parameters to resolving services from the RequestServices collection. Dies resultiert in Klassen, die einfacher getestet werden können.This results in classes that are easier to test.

Entwerfen von Diensten für die AbhängigkeitsinjektionDesign services for dependency injection

Beachten Sie Folgendes beim Entwerfen von Diensten für Dependency Injection:When designing services for dependency injection:

  • Vermeiden Sie zustandsbehaftete statische Klassen und Member.Avoid stateful, static classes and members. Vermeiden Sie das Erstellen eines globalen Zustands, indem Sie Apps stattdessen zur Verwendung von Singletondiensten entwerfen.Avoid creating global state by designing apps to use singleton services instead.
  • Vermeiden Sie die direkte Instanziierung abhängiger Klassen innerhalb von Diensten.Avoid direct instantiation of dependent classes within services. Die direkte Instanziierung koppelt den Code an eine bestimmte Implementierung.Direct instantiation couples the code to a particular implementation.
  • Erstellen Sie kleine, gut gestaltete und einfach zu testende Dienste.Make services small, well-factored, and easily tested.

Wenn eine Klasse viele eingefügte Abhängigkeiten aufweist, ist dies möglicherweise ein Zeichen dafür, dass die Klasse zu viele Aufgaben hat und gegen das Prinzip der einzelnen Verantwortung (SRP, Single Responsibility Principle) verstößt.If a class has a lot of injected dependencies, it might be a sign that the class has too many responsibilities and violates the Single Responsibility Principle (SRP). Versuchen Sie, die Klasse umzugestalten, indem Sie einige ihrer Verantwortung in neue Klassen verschieben.Attempt to refactor the class by moving some of its responsibilities into new classes. Beachten Sie, dass der Fokus der Razor Pages-Seitenmodellklassen und MVC-Controllerklassen auf der Benutzeroberfläche liegt.Keep in mind that Razor Pages page model classes and MVC controller classes should focus on UI concerns.

Löschen von DienstenDisposal of services

Der Container ruft Dispose für die erstellten IDisposable-Typen auf.The container calls Dispose for the IDisposable types it creates. Dienste, die aus dem Container aufgelöst werden, sollten nie vom Entwickler gelöscht werden.Services resolved from the container should never be disposed by the developer. Wenn ein Typ oder eine Factory als Singleton registriert ist, wird das Singleton automatisch vom Container verworfen.If a type or factory is registered as a singleton, the container disposes the singleton automatically.

Im folgenden Beispiel werden die Dienste vom Dienstcontainer erstellt und automatisch verworfen:In the following example, the services are created by the service container and disposed automatically:

public class Service1 : IDisposable
{
    private bool _disposed;

    public void Write(string message)
    {
        Console.WriteLine($"Service1: {message}");
    }

    public void Dispose()
    {
        if (_disposed)
            return;

        Console.WriteLine("Service1.Dispose");
        _disposed = true;
    }
}

public class Service2 : IDisposable
{
    private bool _disposed;

    public void Write(string message)
    {
        Console.WriteLine($"Service2: {message}");
    }

    public void Dispose()
    {
        if (_disposed)
            return;

        Console.WriteLine("Service2.Dispose");
        _disposed = true;
    }
}

public interface IService3
{
    public void Write(string message);
}

public class Service3 : IService3, IDisposable
{
    private bool _disposed;

    public Service3(string myKey)
    {
        MyKey = myKey;
    }

    public string MyKey { get; }

    public void Write(string message)
    {
        Console.WriteLine($"Service3: {message}, MyKey = {MyKey}");
    }

    public void Dispose()
    {
        if (_disposed)
            return;

        Console.WriteLine("Service3.Dispose");
        _disposed = true;
    }
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<Service1>();
    services.AddSingleton<Service2>();
    
    var myKey = Configuration["MyKey"];
    services.AddSingleton<IService3>(sp => new Service3(myKey));

    services.AddRazorPages();
}
public class IndexModel : PageModel
{
    private readonly Service1 _service1;
    private readonly Service2 _service2;
    private readonly IService3 _service3;

    public IndexModel(Service1 service1, Service2 service2, IService3 service3)
    {
        _service1 = service1;
        _service2 = service2;
        _service3 = service3;
    }

    public void OnGet()
    {
        _service1.Write("IndexModel.OnGet");
        _service2.Write("IndexModel.OnGet");
        _service3.Write("IndexModel.OnGet");
    }
}

In der Debuggingkonsole wird nach jeder Aktualisierung der Indexseite die folgende Ausgabe angezeigt:The debug console shows the following output after each refresh of the Index page:

Service1: IndexModel.OnGet
Service2: IndexModel.OnGet
Service3: IndexModel.OnGet
Service1.Dispose

Nicht vom Dienstcontainer erstellte DiensteServices not created by the service container

Betrachten Sie folgenden Code:Consider the following code:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton(new Service1());
    services.AddSingleton(new Service2());

    services.AddRazorPages();
}

Für den Code oben gilt:In the preceding code:

  • werden die Dienstinstanzen nicht vom Dienstcontainer erstellt.The service instances aren't created by the service container.
  • verwirft das Framework die Dienste nicht automatisch.The framework doesn't dispose of the services automatically.
  • Der Entwickler ist für das Löschen der Dienste verantwortlich.The developer is responsible for disposing the services.

IDisposable-Anleitung für vorübergehende and freigegebene InstanzenIDisposable guidance for Transient and shared instances

Weitere Informationen finden Sie unter IDisposable-Leitfaden für vorübergehende und freigegebene Instanzen in Abhängigkeitsinjektion in .NET.See IDisposable guidance for Transient and shared instance in Dependency injection in .NET

Ersetzen von StandarddienstcontainernDefault service container replacement

Weitere Informationen finden Sie unter Ersetzen von Standarddienstcontainern in Abhängigkeitsinjektion in .NET.See Default service container replacement in Dependency injection in .NET

EmpfehlungenRecommendations

Weitere Informationen finden Sie unter Empfehlungen in Abhängigkeitsinjektion in .NET.See Recommendations in Dependency injection in .NET

  • Vermeiden Sie die Verwendung von Dienstlocator-Mustern.Avoid using the service locator pattern. Rufen Sie beispielsweise nicht GetService auf, um eine Dienstinstanz zu erhalten, wenn Sie stattdessen Dependency Injection verwenden können:For example, don't invoke GetService to obtain a service instance when you can use DI instead:

    Falsch:Incorrect:

    Falscher Code

    Richtig:Correct:

    public class MyClass
    {
        private readonly IOptionsMonitor<MyOptions> _optionsMonitor;
    
        public MyClass(IOptionsMonitor<MyOptions> optionsMonitor)
        {
            _optionsMonitor = optionsMonitor;
        }
    
        public void MyMethod()
        {
            var option = _optionsMonitor.CurrentValue.Option;
    
            ...
        }
    }
    
  • Eine andere Dienstlocator-Variante, die Sie vermeiden sollten, ist die Injektion einer Factory, die zur Laufzeit Abhängigkeiten auflöst.Another service locator variation to avoid is injecting a factory that resolves dependencies at runtime. Beide Vorgehensweisen kombinieren Strategien zur Umkehrung der Steuerung.Both of these practices mix Inversion of Control strategies.

  • Vermeiden Sie den statischen Zugriff auf HttpContext (z. B. IHttpContextAccessor.HttpContext).Avoid static access to HttpContext (for example, IHttpContextAccessor.HttpContext).

  • Vermeiden Sie Aufrufe von BuildServiceProvider in ConfigureServices.Avoid calls to BuildServiceProvider in ConfigureServices. BuildServiceProvider wird in der Regel aufgerufen, wenn der Entwickler einen Dienst in ConfigureServices auflösen möchte.Calling BuildServiceProvider typically happens when the developer wants to resolve a service in ConfigureServices. Berücksichtigen Sie beispielsweise den Fall, wenn LoginPath aus der Konfiguration geladen wird.For example, consider the case where the LoginPath is loaded from configuration. Vermeiden Sie den folgenden Ansatz:Avoid the following approach:

    Ungültiger Code beim Aufruf von BuildServiceProvider

    Wenn Sie auf die grüne Wellenlinie unter services.BuildServiceProvider auf der vorherigen Abbildung klicken würden, würde folgende ASP0000-Warnung angezeigt werden:In the preceding image, selecting the green wavy line under services.BuildServiceProvider shows the following ASP0000 warning:

    ASP0000: Der Aufruf von BuildServiceProvider aus dem Anwendungscode führt dazu, dass eine zusätzliche Kopie der Singletondienste erstellt wird.ASP0000 Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Verwenden Sie Alternativen wie Dependency-Injection-Dienste als Parameter für Configure.Consider alternatives such as dependency injecting services as parameters to 'Configure'.

    Durch den Aufruf von BuildServiceProvider wird ein zweiter Container erstellt, der fragmentierte Singletons und Verweise auf Objektgraphen für mehrere Container verursachen kann.Calling BuildServiceProvider creates a second container, which can create torn singletons and cause references to object graphs across multiple containers.

    Eine korrekte Methode zum Abrufen von LoginPath besteht darin, die integrierte Unterstützung von DI des Optionsmusters zu verwenden:A correct way to get LoginPath is to use the options pattern's built-in support for DI:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie();
    
        services.AddOptions<CookieAuthenticationOptions>(
                            CookieAuthenticationDefaults.AuthenticationScheme)
            .Configure<IMyService>((options, myService) =>
            {
                options.LoginPath = myService.GetLoginPath();
            });
    
        services.AddRazorPages();
    }
    
  • Löschbare temporäre Dienste werden vom Container für die Löschung erfasst.Disposable transient services are captured by the container for disposal. Dadurch kann es zu Arbeitsspeicherverlusten kommen, wenn diese vom obersten Container aufgelöst werden.This can turn into a memory leak if resolved from the top level container.

  • Aktivieren Sie die Bereichsüberprüfung, um sicherzustellen, dass die App keine Singletons aufweist, die bereichsbezogene Dienste erfassen.Enable scope validation to make sure the app doesn't have singletons that capture scoped services. Weitere Informationen finden Sie unter Bereichsvalidierung.For more information, see Scope validation.

Wie bei allen Empfehlungen treffen Sie möglicherweise auf Situationen, in denen eine Empfehlung ignoriert werden muss.Like all sets of recommendations, you may encounter situations where ignoring a recommendation is required. Es gibt nur wenige Ausnahmen, die sich meistens auf besondere Fälle innerhalb des Frameworks beziehen.Exceptions are rare, mostly special cases within the framework itself.

Dependency Injection stellt eine Alternative zu statischen bzw. globalen Objektzugriffsmustern dar.DI is an alternative to static/global object access patterns. Sie werden keinen Nutzen aus der Dependency Injection ziehen können, wenn Sie diese mit dem Zugriff auf statische Objekte kombinieren.You may not be able to realize the benefits of DI if you mix it with static object access.

Orchard Core ist ein Anwendungsframework zum Erstellen modularer Anwendung mit mehreren Mandanten in ASP.NET Core.Orchard Core is an application framework for building modular, multi-tenant applications on ASP.NET Core. Weitere Informationen finden Sie in der Orchard Core-Dokumentation.For more information, see the Orchard Core Documentation.

Beispiele zum Erstellen modularer Apps und Apps mit mehreren Mandanten nur mit dem Orchard Core-Framework und ohne den CMS-spezifischen Features finden Sie in den Orchard Core-Beispielen.See the Orchard Core samples for examples of how to build modular and multi-tenant apps using just the Orchard Core Framework without any of its CMS-specific features.

Von Frameworks bereitgestellte DiensteFramework-provided services

Die Startup.ConfigureServices-Methode registriert Dienste, die von der App verwendet werden, einschließlich Plattformfeatures wie Entity Framework Core und ASP.NET Core MVC.The Startup.ConfigureServices method registers services that the app uses, including platform features, such as Entity Framework Core and ASP.NET Core MVC. Zunächst enthält die in ConfigureServices bereitgestellte IServiceCollection die vom Framework definierten Dienste, abhängig davon, wie der Host konfiguriert wurde.Initially, the IServiceCollection provided to ConfigureServices has services defined by the framework depending on how the host was configured. Für Apps, die auf ASP.NET Core-Vorlagen basieren, registriert das Framework mehr als 250 Dienste.For apps based on the ASP.NET Core templates, the framework registers more than 250 services.

In der folgenden Tabelle finden Sie eine kleine Stichprobe der vom Framework registrierten Dienste:The following table lists a small sample of these framework-registered services:

DiensttypService Type LebensdauerLifetime
Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory Transient (vorübergehend)Transient
IHostApplicationLifetime SingletonSingleton
IWebHostEnvironment SingletonSingleton
Microsoft.AspNetCore.Hosting.IStartup SingletonSingleton
Microsoft.AspNetCore.Hosting.IStartupFilter Transient (vorübergehend)Transient
Microsoft.AspNetCore.Hosting.Server.IServer SingletonSingleton
Microsoft.AspNetCore.Http.IHttpContextFactory Transient (vorübergehend)Transient
Microsoft.Extensions.Logging.ILogger<TCategoryName> SingletonSingleton
Microsoft.Extensions.Logging.ILoggerFactory SingletonSingleton
Microsoft.Extensions.ObjectPool.ObjectPoolProvider SingletonSingleton
Microsoft.Extensions.Options.IConfigureOptions<TOptions> Transient (vorübergehend)Transient
Microsoft.Extensions.Options.IOptions<TOptions> SingletonSingleton
System.Diagnostics.DiagnosticSource SingletonSingleton
System.Diagnostics.DiagnosticListener SingletonSingleton

Zusätzliche RessourcenAdditional resources

Von Steve Smith, Scott Addie, und Brandon DahlerBy Steve Smith, Scott Addie, and Brandon Dahler

ASP.NET Core unterstützt das Softwareentwurfsmuster Abhängigkeitsinjektion. Damit kann eine Umkehrung der Steuerung (Inversion of Control, IoC) zwischen Klassen und ihren Abhängigkeiten erreicht werden.ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies.

Weitere Informationen zur Abhängigkeitsinjektion innerhalb von MVC-Controllern finden Sie unter Dependency Injection in Controller in ASP.NET Core.For more information specific to dependency injection within MVC controllers, see Dependency Injection in Controller in ASP.NET Core.

Anzeigen oder Herunterladen von Beispielcode (Vorgehensweise zum Herunterladen)View or download sample code (how to download)

Übersicht über AbhängigkeitsinjektionOverview of dependency injection

Eine Abhängigkeit ist ein beliebiges Objekt, das ein anderes Objekt benötigt.A dependency is any object that another object requires. Überprüfen Sie die folgende MyDependency-Klasse mit einer WriteMessage-Methode, von der andere Klassen in einer App abhängen:Examine the following MyDependency class with a WriteMessage method that other classes in an app depend upon:

public class MyDependency
{
    public MyDependency()
    {
    }

    public Task WriteMessage(string message)
    {
        Console.WriteLine(
            $"MyDependency.WriteMessage called. Message: {message}");

        return Task.FromResult(0);
    }
}

Eine Instanz der Klasse MyDependency kann erstellt werden, um die WriteMessage-Methode einer Klasse zur Verfügung zu stellen.An instance of the MyDependency class can be created to make the WriteMessage method available to a class. Die Klasse MyDependency ist eine Abhängigkeit der Klasse IndexModel:The MyDependency class is a dependency of the IndexModel class:

public class IndexModel : PageModel
{
    MyDependency _dependency = new MyDependency();

    public async Task OnGetAsync()
    {
        await _dependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}

Die Klasse erstellt die Instanz MyDependency und hängt direkt von dieser ab.The class creates and directly depends on the MyDependency instance. Codeabhängigkeiten (wie im vorherigen Beispiel) sind problematisch und sollten aus folgenden Gründen vermieden werden:Code dependencies (such as the previous example) are problematic and should be avoided for the following reasons:

  • Um MyDependency durch eine andere Implementierung zu ersetzen, muss die Klasse geändert werden.To replace MyDependency with a different implementation, the class must be modified.
  • Wenn MyDependency über Abhängigkeiten verfügt, müssen diese von der Klasse konfiguriert werden.If MyDependency has dependencies, they must be configured by the class. In einem großen Projekt mit mehreren Klassen, die von MyDependency abhängig sind, wird der Konfigurationscode über die App verteilt.In a large project with multiple classes depending on MyDependency, the configuration code becomes scattered across the app.
  • Diese Implementierung ist nicht für Komponententests geeignet.This implementation is difficult to unit test. Die App sollte eine MyDependency-Modell- oder Stubklasse verwenden, was mit diesem Ansatz nicht möglich ist.The app should use a mock or stub MyDependency class, which isn't possible with this approach.

Die Abhängigkeitsinjektion löst dieses Problem mithilfe der folgenden Schritte:Dependency injection addresses these problems through:

  • Die Verwendung einer Schnittstelle oder Basisklasse zur Abstraktion der Abhängigkeitsimplementierung.The use of an interface or base class to abstract the dependency implementation.
  • Registrierung der Abhängigkeit in einem Dienstcontainer.Registration of the dependency in a service container. ASP.NET Core stellt einen integrierten Dienstcontainer (IServiceProvider) bereit.ASP.NET Core provides a built-in service container, IServiceProvider. Die Dienste werden in der App-Methode Startup.ConfigureServices registriert.Services are registered in the app's Startup.ConfigureServices method.
  • Die Injektion des Diensts in den Konstruktor der Klasse, wo er verwendet wird.Injection of the service into the constructor of the class where it's used. Das Framework erstellt eine Instanz der Abhängigkeit und entfernt diese, wenn sie nicht mehr benötigt wird.The framework takes on the responsibility of creating an instance of the dependency and disposing of it when it's no longer needed.

In der Beispiel-App definiert die IMyDependency-Schnittstelle eine Methode, die der Dienst für die App bereitstellt:In the sample app, the IMyDependency interface defines a method that the service provides to the app:

public interface IMyDependency
{
    Task WriteMessage(string message);
}

Diese Schnittstelle wird durch einen konkreten Typ (MyDependency) implementiert:This interface is implemented by a concrete type, MyDependency:

public class MyDependency : IMyDependency
{
    private readonly ILogger<MyDependency> _logger;

    public MyDependency(ILogger<MyDependency> logger)
    {
        _logger = logger;
    }

    public Task WriteMessage(string message)
    {
        _logger.LogInformation(
            "MyDependency.WriteMessage called. Message: {Message}", 
            message);

        return Task.FromResult(0);
    }
}

MyDependency fordert einen ILogger<TCategoryName> beim zugehörigen Konstruktor an.MyDependency requests an ILogger<TCategoryName> in its constructor. Die Abhängigkeitsinjektion wird häufig als Verkettung verwendet.It's not unusual to use dependency injection in a chained fashion. Jede angeforderte Abhängigkeit fordert wiederum ihre eigenen Abhängigkeiten an.Each requested dependency in turn requests its own dependencies. Der Container löst die Abhängigkeiten im Diagramm auf und gibt den vollständig aufgelösten Dienst zurück.The container resolves the dependencies in the graph and returns the fully resolved service. Die gesammelten aufzulösenden Abhängigkeiten werden als Abhängigkeitsstruktur, Abhängigkeitsdiagramm oder Objektdiagramm bezeichnet.The collective set of dependencies that must be resolved is typically referred to as a dependency tree, dependency graph, or object graph.

IMyDependency und ILogger<TCategoryName> müssen im Dienstcontainer registriert werden.IMyDependency and ILogger<TCategoryName> must be registered in the service container. IMyDependency ist in Startup.ConfigureServices registriert.IMyDependency is registered in Startup.ConfigureServices. ILogger<TCategoryName> wird von der Protokollierungsabstraktionsinfrastruktur registriert. Es handelt sich also um einen von einem Framework bereitgestellten Dienst, der standardmäßig vom Framework registriert wird.ILogger<TCategoryName> is registered by the logging abstractions infrastructure, so it's a framework-provided service registered by default by the framework.

Der Container löst ILogger<TCategoryName> unter Verwendung der (generischen) offenen Typen auf, wodurch die Notwendigkeit entfällt, jeden (generischen) konstruierten Typ zu registrieren:The container resolves ILogger<TCategoryName> by taking advantage of (generic) open types, eliminating the need to register every (generic) constructed type:

services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));

In der Beispiel-App ist der Dienst IMyDependency mit dem konkreten Typ MyDependency registriert.In the sample app, the IMyDependency service is registered with the concrete type MyDependency. Die Registrierung schränkt die Lebensdauer des Diensts auf die Lebensdauer einer einzelnen Anforderung ein.The registration scopes the service lifetime to the lifetime of a single request. Auf die Dienstlebensdauer wird später in diesem Artikel eingegangen.Service lifetimes are described later in this topic.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));

    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}

Hinweis

Jede services.Add{SERVICE_NAME}-Erweiterungsmethode fügt Dienste hinzu und konfiguriert diese möglicherweise.Each services.Add{SERVICE_NAME} extension method adds, and potentially configures, services. services.AddControllersWithViews, services.AddRazorPages und services.AddControllers fügen beispielsweise die Dienste hinzu, die ASP.NET Core-Apps benötigen.For example, services.AddControllersWithViews, services.AddRazorPages, and services.AddControllers adds the services ASP.NET Core apps require. Es wird empfohlen, dass Apps dieser Konvention folgen.We recommended that apps follow this convention. Platzieren Sie Erweiterungsmethoden im Namespace Microsoft.Extensions.DependencyInjection, um Gruppen von Dienstregistrierungen zu kapseln.Place extension methods in the Microsoft.Extensions.DependencyInjection namespace to encapsulate groups of service registrations. Durch Einschließen des Namespaceteils Microsoft.Extensions.DependencyInjection für DI-Erweiterungsmethoden ergibt sich für diese auch Folgendes:Including the namespace portion Microsoft.Extensions.DependencyInjection for DI extension methods also:

  • Sie können auch in IntelliSense angezeigt werden, ohne dass zusätzliche using-Blöcke hinzugefügt werden.Allows them to be displayed in IntelliSense without adding additional using blocks.
  • Es werden übermäßige using-Anweisungen in der Startup-Klasse verhindert, von der aus diese Erweiterungsmethoden in der Regel aufgerufen werden.Prevents excessive using statements in the Startup class where these extension methods are typically called from.

Wenn für den Dienstkonstruktor ein integrierter Typ erforderlich ist, z. B. string, kann dieser Typ über Konfiguration oder das Optionsmuster eingefügt werden:If the service's constructor requires a built in type, such as a string, the type can be injected by using configuration or the options pattern:

public class MyDependency : IMyDependency
{
    public MyDependency(IConfiguration config)
    {
        var myStringValue = config["MyStringKey"];

        // Use myStringValue
    }

    ...
}

Eine Instanz des Diensts wird über den Konstruktor einer Klasse angefordert, in der der Dienst verwendet wird, und einem privaten Feld zugewiesen.An instance of the service is requested via the constructor of a class where the service is used and assigned to a private field. Das Feld wird verwendet, um auf den Dienst bei Bedarf über die gesamte Klasse zuzugreifen.The field is used to access the service as necessary throughout the class.

In der Beispiel-App wird die Instanz IMyDependency angefordert, und mit ihr wird die App-Methode WriteMessage aufgerufen:In the sample app, the IMyDependency instance is requested and used to call the service's WriteMessage method:

public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(
        IMyDependency myDependency, 
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _myDependency = myDependency;
        OperationService = operationService;
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = singletonInstanceOperation;
    }

    public OperationService OperationService { get; }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public async Task OnGetAsync()
    {
        await _myDependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}

In den Start eingefügte DiensteServices injected into Startup

Bei Verwendung des generischen Hosts (IHostBuilder) können nur die folgenden Diensttypen in den Startup-Konstruktor eingefügt werden:Only the following service types can be injected into the Startup constructor when using the Generic Host (IHostBuilder):

Dienste können in Startup.Configure eingefügt werden:Services can be injected into Startup.Configure:

public void Configure(IApplicationBuilder app, IOptions<MyOptions> options)
{
    ...
}

Weitere Informationen finden Sie unter Anwendungsstart in ASP.NET Core.For more information, see Anwendungsstart in ASP.NET Core.

Von Frameworks bereitgestellte DiensteFramework-provided services

Die Methode Startup.ConfigureServices definiert die von der App verwendeten Dienste. Dies umfasst auch Plattformfeatures wie Entity Framework Core und ASP.NET Core MVC.The Startup.ConfigureServices method is responsible for defining the services that the app uses, including platform features, such as Entity Framework Core and ASP.NET Core MVC. Zunächst enthält die in ConfigureServices bereitgestellte IServiceCollection die vom Framework definierten Dienste, abhängig davon, wie der Host konfiguriert wurde.Initially, the IServiceCollection provided to ConfigureServices has services defined by the framework depending on how the host was configured. Es ist nicht ungewöhnlich, dass das Framework Hunderte von Diensten für eine auf einer ASP.NET Core-Vorlage basierende App registriert.It's not uncommon for an app based on an ASP.NET Core template to have hundreds of services registered by the framework. In der folgenden Tabelle finden Sie eine kleine Auswahl der Dienste, die vom Framework registriert werden können.A small sample of framework-registered services is listed in the following table.

DiensttypService Type LebensdauerLifetime
Microsoft.AspNetCore.Hosting.Builder.IApplicationBuilderFactory Transient (vorübergehend)Transient
Microsoft.AspNetCore.Hosting.IApplicationLifetime SingletonSingleton
Microsoft.AspNetCore.Hosting.IHostingEnvironment SingletonSingleton
Microsoft.AspNetCore.Hosting.IStartup SingletonSingleton
Microsoft.AspNetCore.Hosting.IStartupFilter Transient (vorübergehend)Transient
Microsoft.AspNetCore.Hosting.Server.IServer SingletonSingleton
Microsoft.AspNetCore.Http.IHttpContextFactory Transient (vorübergehend)Transient
Microsoft.Extensions.Logging.ILogger<TCategoryName> SingletonSingleton
Microsoft.Extensions.Logging.ILoggerFactory SingletonSingleton
Microsoft.Extensions.ObjectPool.ObjectPoolProvider SingletonSingleton
Microsoft.Extensions.Options.IConfigureOptions<TOptions> Transient (vorübergehend)Transient
Microsoft.Extensions.Options.IOptions<TOptions> SingletonSingleton
System.Diagnostics.DiagnosticSource SingletonSingleton
System.Diagnostics.DiagnosticListener SingletonSingleton

Registrieren weiterer Dienste mit ErweiterungsmethodenRegister additional services with extension methods

Wenn eine Dienstsammlungs-Erweiterungsmethode verfügbar ist, um einen Dienst (und ggf. seine abhängigen Dienste) zu registrieren, ist die Konvention, eine einzige Add{SERVICE_NAME}-Erweiterungsmethode zu verwenden, um alle von diesem Dienst benötigten Dienste zu registrieren.When a service collection extension method is available to register a service (and its dependent services, if required), the convention is to use a single Add{SERVICE_NAME} extension method to register all of the services required by that service. Der folgende Code ist ein Beispiel dafür, wie mit den Erweiterungsmethoden AddDbContext<TContext> und AddIdentityCore zusätzliche Dienste zum Container hinzugefügt werden:The following code is an example of how to add additional services to the container using the extension methods AddDbContext<TContext> and AddIdentityCore:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    ...
}

Weitere Informationen finden Sie in der ServiceCollection-Klasse in der API-Dokumentation.For more information, see the ServiceCollection class in the API documentation.

DienstlebensdauerService lifetimes

Wählen Sie eine geeignete Lebensdauer für jeden registrierten Dienst aus.Choose an appropriate lifetime for each registered service. ASP.NET Core-Dienste können mit folgender Lebensdauer konfiguriert werden:ASP.NET Core services can be configured with the following lifetimes:

Transient (vorübergehend)Transient

Kurzlebige Dienste (AddTransient) werden bei jeder Anforderung aus dem Dienstcontainer neu erstellt.Transient lifetime services (AddTransient) are created each time they're requested from the service container. Diese Lebensdauer ist am besten für einfache, zustandslose Dienste geeignet.This lifetime works best for lightweight, stateless services.

In Apps, die Anforderungen verarbeiten, werden vorübergehende Dienste am Ende der Anforderung verworfen.In apps that process requests, transient services are disposed at the end of the request.

BereichsbezogenScoped

Dienste mit bereichsbezogener Lebensdauer (AddScoped) werden einmal pro Clientanforderung (-verbindung) erstellt.Scoped lifetime services (AddScoped) are created once per client request (connection).

In Apps, die Anforderungen verarbeiten, werden bereichsbezogene Dienste am Ende der Anforderung verworfen.In apps that process requests, scoped services are disposed at the end of the request.

Warnung

Wenn Sie einen bereichsbezogenen Dienst in einer Middleware verwenden, müssen Sie den Dienst in die Invoke- oder InvokeAsync-Methode einfügen.When using a scoped service in a middleware, inject the service into the Invoke or InvokeAsync method. Fügen Sie ihn nicht über Konstruktorinjektion ein, da hierdurch der Dienst ein Verhalten wie ein Singleton zeigt.Don't inject via constructor injection because it forces the service to behave like a singleton. Weitere Informationen finden Sie unter Schreiben von benutzerdefinierter ASP.NET Core-Middleware.For more information, see Schreiben von benutzerdefinierter ASP.NET Core-Middleware.

SingletonSingleton

Dienste mit Singleton-Lebensdauer (AddSingleton) werden bei der ersten Anforderung erstellt (bzw. wenn Startup.ConfigureServices ausgeführt wird, und eine Instanz bei der Dienstregistrierung angegeben wird).Singleton lifetime services (AddSingleton) are created the first time they're requested (or when Startup.ConfigureServices is run and an instance is specified with the service registration). Jeder nachfolgenden Anforderung verwendet die gleiche Instanz.Every subsequent request uses the same instance. Wenn die App ein Verhalten vom Typ „Singleton“ erfordert, wird empfohlen, den Dienstcontainer die Dienstlebensdauer verwalten zu lassen.If the app requires singleton behavior, allowing the service container to manage the service's lifetime is recommended. Implementieren Sie nicht das Designmuster „Singleton“ und stellen Sie Benutzercode bereit, um die Objektlebensdauer in der Klasse zu verwalten.Don't implement the singleton design pattern and provide user code to manage the object's lifetime in the class.

In Apps, die Anforderungen verarbeiten, werden Singleton-Dienste verworfen, wenn der ServiceProvider beim Herunterfahren der App verworfen wird.In apps that process requests, singleton services are disposed when the ServiceProvider is disposed at app shutdown.

Warnung

Es ist riskant, einen bereichsbezogenen Dienst über ein Singleton aufzulösen.It's dangerous to resolve a scoped service from a singleton. Möglicherweise weist der Dienst bei der Verarbeitung nachfolgender Anforderungen einen falschen Status auf.It may cause the service to have incorrect state when processing subsequent requests.

DienstregistrierungsmethodenService registration methods

Methoden zur Erweiterung der Dienstregistrierung bieten Überladungen, die in bestimmten Szenarios hilfreich sind.Service registration extension methods offer overloads that are useful in specific scenarios.

MethodeMethod AutomatischeAutomatic
Objektobject
bereinigungdisposal
MehrereMultiple
Implementierungenimplementations
ArgumentübergabePass args
Add{LIFETIME}<{SERVICE}, {IMPLEMENTATION}>()
Beispiel:Example:
services.AddSingleton<IMyDep, MyDep>();
JaYes JaYes NeinNo
Add{LIFETIME}<{SERVICE}>(sp => new {IMPLEMENTATION})
Beispiele:Examples:
services.AddSingleton<IMyDep>(sp => new MyDep());
services.AddSingleton<IMyDep>(sp => new MyDep("A string!"));
JaYes JaYes JaYes
Add{LIFETIME}<{IMPLEMENTATION}>()
Beispiel:Example:
services.AddSingleton<MyDep>();
JaYes NeinNo NeinNo
AddSingleton<{SERVICE}>(new {IMPLEMENTATION})
Beispiele:Examples:
services.AddSingleton<IMyDep>(new MyDep());
services.AddSingleton<IMyDep>(new MyDep("A string!"));
NeinNo JaYes JaYes
AddSingleton(new {IMPLEMENTATION})
Beispiele:Examples:
services.AddSingleton(new MyDep());
services.AddSingleton(new MyDep("A string!"));
NeinNo NeinNo JaYes

Weitere Informationen zum Löschen von Typen finden Sie im Abschnitt Löschen von Diensten.For more information on type disposal, see the Disposal of services section. Ein häufiges Szenario für mehrere Implementierungen ist Typen zu Testzwecken simulieren.A common scenario for multiple implementations is mocking types for testing.

Das Registrieren eines Diensts mit nur einem Implementierungstyp entspricht dem Registrieren dieses Diensts mit demselben Implementierungs- und Diensttyp.Registering a service with only an implementation type is equivalent to registering that service with the same implementation and service type. Aus diesem Grund können nicht mehrere Implementierungen eines Diensts mithilfe von Methoden registriert werden, die keinen expliziten Diensttyp erwarten.This is why multiple implementations of a service cannot be registered using the methods that don't take an explicit service type. Solche Methoden können mehrere Instanzen eines Diensts registrieren, die dann jedoch alle denselben Implementierungstyp aufweisen.These methods can register multiple instances of a service, but they will all have the same implementation type.

Alle oben genannten Dienstregistrierungsmethoden können zum Registrieren mehrerer Dienstinstanzen desselben Diensttyps verwendet werden.Any of the above service registration methods can be used to register multiple service instances of the same service type. Im folgenden Beispiel wird AddSingleton zweimal mit IMyDependency als Diensttyp aufgerufen.In the following example, AddSingleton is called twice with IMyDependency as the service type. Mit dem zweiten Aufruf von AddSingleton wird der vorhandene Singleton überschrieben, wenn er als IMyDependency aufgelöst wurde. Wenn mehrere Dienste über IEnumerable<IMyDependency> aufgelöst werden, wird der neue Singleton hinzugefügt und der alte beibehalten.The second call to AddSingleton overrides the previous one when resolved as IMyDependency and adds to the previous one when multiple services are resolved via IEnumerable<IMyDependency>. Dienste werden beim Auflösen mit IEnumerable<{SERVICE}> in der Reihenfolge angezeigt, in der sie registriert wurden.Services appear in the order they were registered when resolved via IEnumerable<{SERVICE}>.

services.AddSingleton<IMyDependency, MyDependency>();
services.AddSingleton<IMyDependency, DifferentDependency>();

public class MyService
{
    public MyService(IMyDependency myDependency, 
       IEnumerable<IMyDependency> myDependencies)
    {
        Trace.Assert(myDependency is DifferentDependency);

        var dependencyArray = myDependencies.ToArray();
        Trace.Assert(dependencyArray[0] is MyDependency);
        Trace.Assert(dependencyArray[1] is DifferentDependency);
    }
}

Das Framework stellt außerdem TryAdd{LIFETIME}-Erweiterungsmethoden bereit, die den Dienst nur registrieren, wenn noch keine Implementierung registriert ist.The framework also provides TryAdd{LIFETIME} extension methods, which register the service only if there isn't already an implementation registered.

Im folgenden Beispiel registriert der AddSingleton-Aufruf MyDependency als Implementierung für IMyDependency.In the following example, the call to AddSingleton registers MyDependency as an implementation for IMyDependency. Der Aufruf von TryAddSingleton hat keine Auswirkung, da IMyDependency bereits eine registrierte Implementierung aufweist.The call to TryAddSingleton has no effect because IMyDependency already has a registered implementation.

services.AddSingleton<IMyDependency, MyDependency>();
// The following line has no effect:
services.TryAddSingleton<IMyDependency, DifferentDependency>();

public class MyService
{
    public MyService(IMyDependency myDependency, 
        IEnumerable<IMyDependency> myDependencies)
    {
        Trace.Assert(myDependency is MyDependency);
        Trace.Assert(myDependencies.Single() is MyDependency);
    }
}

Weitere Informationen finden Sie unter:For more information, see:

TryAddEnumerable(ServiceDescriptor)-Methoden registrieren den Dienst nur, wenn es nicht bereits eine Implementierung des gleichen Typs gibt.TryAddEnumerable(ServiceDescriptor) methods only register the service if there isn't already an implementation of the same type. Mehrere Dienste werden über IEnumerable<{SERVICE}> aufgelöst.Multiple services are resolved via IEnumerable<{SERVICE}>. Beim Registrieren von Diensten möchte der Entwickler nur eine Instanz hinzufügen, wenn nicht bereits eine Instanz vom gleichen Typ hinzugefügt wurde.When registering services, the developer only wants to add an instance if one of the same type hasn't already been added. Diese Methode wird in der Regel von Bibliotheksautoren verwendet, um zu vermeiden, dass zwei Kopien einer Instanz im Container registriert werden.Generally, this method is used by library authors to avoid registering two copies of an instance in the container.

Im folgenden Beispiel registriert die erste Zeile MyDep für IMyDep1.In the following example, the first line registers MyDep for IMyDep1. Die zweite Zeile registriert MyDep für IMyDep2.The second line registers MyDep for IMyDep2. Die dritte Zeile hat keine Auswirkungen, da es für IMyDep1 bereits eine registrierte Implementierung von MyDep gibt:The third line has no effect because IMyDep1 already has a registered implementation of MyDep:

public interface IMyDep1 {}
public interface IMyDep2 {}

public class MyDep : IMyDep1, IMyDep2 {}

services.TryAddEnumerable(ServiceDescriptor.Singleton<IMyDep1, MyDep>());
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMyDep2, MyDep>());
// Two registrations of MyDep for IMyDep1 is avoided by the following line:
services.TryAddEnumerable(ServiceDescriptor.Singleton<IMyDep1, MyDep>());

Verhalten von Constructor InjectionConstructor injection behavior

Dienste können durch zwei Mechanismen aufgelöst werden:Services can be resolved by two mechanisms:

  • IServiceProvider
  • ActivatorUtilities: Lässt die Erstellung von Objekten ohne Dienstregistrierung im Dependency-Injection-Container zuActivatorUtilities: Permits object creation without service registration in the dependency injection container. ActivatorUtilities wird mit Abstraktionen für Benutzer verwendet. Dazu zählen Taghilfsprogramme, MVC-Controller und Modellbindungen.ActivatorUtilities is used with user-facing abstractions, such as Tag Helpers, MVC controllers, and model binders.

Konstruktoren können Argumente akzeptieren, die nicht durch Abhängigkeitsinjektion bereitgestellt werden. Die Argumente müssen jedoch Standardwerte zuweisen.Constructors can accept arguments that aren't provided by dependency injection, but the arguments must assign default values.

Wenn Dienste durch IServiceProvider oder ActivatorUtilities aufgelöst werden, benötigt die Konstruktorinjektion einen öffentlichen Konstruktor.When services are resolved by IServiceProvider or ActivatorUtilities, constructor injection requires a public constructor.

Wenn Dienste durch ActivatorUtilities aufgelöst werden, erfordert die Konstruktorinjektion, dass nur ein anwendbarer Konstruktor vorhanden ist.When services are resolved by ActivatorUtilities, constructor injection requires that only one applicable constructor exists. Konstruktorüberladungen werden unterstützt. Es darf jedoch nur eine Überladung vorhanden sein, deren Argumente alle durch Dependency Injection erfüllt werden können.Constructor overloads are supported, but only one overload can exist whose arguments can all be fulfilled by dependency injection.

Entity Framework-KontexteEntity Framework contexts

Entity Framework-Kontexte werden einem Dienstcontainer normalerweise mithilfe der bereichsbezogenen Lebensdauer hinzugefügt, da Datenbankvorgänge von Web-Apps normalerweise auf den Clientanforderungsbereich bezogen werden.Entity Framework contexts are usually added to the service container using the scoped lifetime because web app database operations are normally scoped to the client request. Der Bereich einer Standardlebensdauer wird festgelegt, wenn eine Lebensdauer nicht von einer AddDbContext<TContext>-Überladung angegeben wird, wenn der Datenbankkontext registriert wird.The default lifetime is scoped if a lifetime isn't specified by an AddDbContext<TContext> overload when registering the database context. Dienste einer festgelegten Lebensdauer sollten keinen Datenbankkontext mit einer kürzeren Lebensdauer als die des Dienstes verwenden.Services of a given lifetime shouldn't use a database context with a shorter lifetime than the service.

Lebensdauer und RegistrierungsoptionenLifetime and registration options

Um den Unterschied zwischen der Lebensdauer und den Registrierungsoptionen zu demonstrieren, betrachten Sie die folgenden Schnittstellen, die Aufgaben als Vorgänge mit einem eindeutigen Bezeichner (OperationId) darstellen.To demonstrate the difference between the lifetime and registration options, consider the following interfaces that represent tasks as an operation with a unique identifier, OperationId. Je nachdem, wie die Dienstlebensdauer für die folgenden Schnittstellen konfiguriert ist, stellt der Container auf Anforderung einer Klasse entweder die gleiche oder eine andere Instanz des Diensts zur Verfügung:Depending on how the lifetime of an operations service is configured for the following interfaces, the container provides either the same or a different instance of the service when requested by a class:

public interface IOperation
{
    Guid OperationId { get; }
}

public interface IOperationTransient : IOperation
{
}

public interface IOperationScoped : IOperation
{
}

public interface IOperationSingleton : IOperation
{
}

public interface IOperationSingletonInstance : IOperation
{
}

Die Schnittstellen sind in die Klasse Operation implementiert.The interfaces are implemented in the Operation class. Der Operation-Konstruktor generiert eine GUID, wenn noch keine angegeben ist:The Operation constructor generates a GUID if one isn't supplied:

public class Operation : IOperationTransient, 
    IOperationScoped, 
    IOperationSingleton, 
    IOperationSingletonInstance
{
    public Operation() : this(Guid.NewGuid())
    {
    }

    public Operation(Guid id)
    {
        OperationId = id;
    }

    public Guid OperationId { get; private set; }
}

OperationService ist registriert und hängt von jedem anderen Operation-Typ ab.An OperationService is registered that depends on each of the other Operation types. Wenn OperationService über die Abhängigkeitsinjektion angefordert wird, wird entweder eine neue Instanz jedes Diensts oder eine vorhandene Instanz basierend auf der Lebensdauer des abhängigen Diensts zurückgegeben.When OperationService is requested via dependency injection, it receives either a new instance of each service or an existing instance based on the lifetime of the dependent service.

  • Wenn vorübergehende Dienste bei der Anforderung aus dem Container erstellt werden, ist die OperationId von Dienst IOperationTransient anders als die OperationId von OperationService.When transient services are created when requested from the container, the OperationId of the IOperationTransient service is different than the OperationId of the OperationService. OperationService erhält eine neue Instanz der Klasse IOperationTransient.OperationService receives a new instance of the IOperationTransient class. Der OperationId-Wert der neuen Instanz ist anders.The new instance yields a different OperationId.
  • Wenn bereichsbezogene Dienste pro Clientanforderung erstellt werden, ist die OperationId in Dienst IOperationScoped und OperationService identisch innerhalb einer Clientanforderung.When scoped services are created per client request, the OperationId of the IOperationScoped service is the same as that of OperationService within a client request. Clientanforderungsübergreifend haben die beiden Dienste jedoch einen anderen gemeinsamen OperationId-Wert.Across client requests, both services share a different OperationId value.
  • Wenn Singleton- und Singletoninstanzdienste einmal erstellt und für alle Clientanforderungen und alle Dienste verwendet werden, ist OperationId für alle Dienstanforderungen identisch.When singleton and singleton-instance services are created once and used across all client requests and all services, the OperationId is constant across all service requests.
public class OperationService
{
    public OperationService(
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)
    {
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = instanceOperation;
    }

    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }
}

In Startup.ConfigureServices wird jeder Typ entsprechend seiner benannten Lebensdauer dem Container hinzugefügt:In Startup.ConfigureServices, each type is added to the container according to its named lifetime:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));

    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}

Der Dienst IOperationSingletonInstance verwendet eine bestimmte Instanz mit einer bekannten ID von Guid.Empty.The IOperationSingletonInstance service is using a specific instance with a known ID of Guid.Empty. Die Verwendung dieses Typs ist eindeutig (die GUID besteht ausschließlich aus Nullen (0)).It's clear when this type is in use (its GUID is all zeroes).

Die Beispiel-App zeigt die Objektlebensdauer innerhalb einer Anforderung und zwischen einzelnen Anforderungen an.The sample app demonstrates object lifetimes within and between individual requests. Ihre Klasse IndexModel fordert jeden IOperation- und OperationService-Typ an.The sample app's IndexModel requests each kind of IOperation type and the OperationService. Die Seite zeigt dann alle OperationId-Werte der Seitenmodellklasse und des Diensts über Eigenschaftenzuweisungen an:The page then displays all of the page model class's and service's OperationId values through property assignments:

public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(
        IMyDependency myDependency, 
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _myDependency = myDependency;
        OperationService = operationService;
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = singletonInstanceOperation;
    }

    public OperationService OperationService { get; }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public async Task OnGetAsync()
    {
        await _myDependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}

Zwei folgende Ausgaben zeigen die Ergebnisse von zwei Anforderungen:Two following output shows the results of two requests:

Erste Anforderung:First request:

Controllervorgänge:Controller operations:

Vorübergehend: d233e165-f417-469b-a866-1cf1935d2518Transient: d233e165-f417-469b-a866-1cf1935d2518
Bereichsbezogen: 5d997e2d-55f5-4a64-8388-51c4e3a1ad19Scoped: 5d997e2d-55f5-4a64-8388-51c4e3a1ad19
Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
Instanz: 00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

OperationService-Vorgänge:OperationService operations:

Vorübergehend: c6b049eb-1318-4e31-90f1-eb2dd849ff64Transient: c6b049eb-1318-4e31-90f1-eb2dd849ff64
Bereichsbezogen: 5d997e2d-55f5-4a64-8388-51c4e3a1ad19Scoped: 5d997e2d-55f5-4a64-8388-51c4e3a1ad19
Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
Instanz: 00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

Zweite Anforderung:Second request:

Controllervorgänge:Controller operations:

Vorübergehend: b63bd538-0a37-4ff1-90ba-081c5138dda0Transient: b63bd538-0a37-4ff1-90ba-081c5138dda0
Bereichsbezogen: 31e820c5-4834-4d22-83fc-a60118acb9f4Scoped: 31e820c5-4834-4d22-83fc-a60118acb9f4
Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
Instanz: 00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

OperationService-Vorgänge:OperationService operations:

Vorübergehend: c4cbacb8-36a2-436d-81c8-8c1b78808aafTransient: c4cbacb8-36a2-436d-81c8-8c1b78808aaf
Bereichsbezogen: 31e820c5-4834-4d22-83fc-a60118acb9f4Scoped: 31e820c5-4834-4d22-83fc-a60118acb9f4
Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9Singleton: 01271bc1-9e31-48e7-8f7c-7261b040ded9
Instanz: 00000000-0000-0000-0000-000000000000Instance: 00000000-0000-0000-0000-000000000000

Beachten Sie, welche der OperationId-Werte innerhalb einer Anforderung und zwischen Anforderungen variieren:Observe which of the OperationId values vary within a request and between requests:

  • Objekte vom Typ Vorübergehend sind immer unterschiedlich.Transient objects are always different. Der vorübergehende OperationId-Wert für die ersten und zweiten Clientanforderungen ist für beide OperationService-Vorgänge und clientanforderungsübergreifend unterschiedlich.The transient OperationId value for both the first and second client requests are different for both OperationService operations and across client requests. Eine neue Instanz wird für jede Dienstanforderung und jede Clientanforderung bereitgestellt.A new instance is provided to each service request and client request.
  • Bereichsbezogene Objekte sind innerhalb einer Clientanforderung identisch, clientanforderungsübergreifend sind sie jedoch unterschiedlich.Scoped objects are the same within a client request but different across client requests.
  • Objekte vom Typ Singleton sind bei jedem Objekt und in jeder Anforderung identisch (unabhängig davon, ob eine Operation-Instanz in Startup.ConfigureServices bereitgestellt wird).Singleton objects are the same for every object and every request regardless of whether an Operation instance is provided in Startup.ConfigureServices.

Abrufen von Diensten aus „Main“Call services from main

Erstellen Sie IServiceScope mit IServiceScopeFactory.CreateScope, um einen bereichsbezogenen Dienst innerhalb des Anwendungsbereichs aufzulösen.Create an IServiceScope with IServiceScopeFactory.CreateScope to resolve a scoped service within the app's scope. Dieser Ansatz eignet sich gut dafür, beim Start auf einen bereichsbezogenen Dienst zuzugreifen und Initialisierungsaufgaben auszuführen.This approach is useful to access a scoped service at startup to run initialization tasks. Das folgende Beispiel veranschaulicht, wie man einen Kontext für MyScopedService in Program.Main erhält:The following example shows how to obtain a context for the MyScopedService in Program.Main:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = CreateWebHostBuilder(args).Build();

        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var serviceContext = services.GetRequiredService<MyScopedService>();
                // Use the context here
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred.");
            }
        }

        await host.RunAsync();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

BereichsvalidierungScope validation

Wenn die App in der Entwicklungsumgebung ausgeführt wird, überprüft der Standarddienstanbieter, ob:When the app is running in the Development environment, the default service provider performs checks to verify that:

  • Bereichsbezogene Dienste nicht direkt oder indirekt vom Stammdienstanbieter aufgelöst werdenScoped services aren't directly or indirectly resolved from the root service provider.
  • Bereichsbezogene Dienste nicht direkt oder indirekt in Singletons eingefügt werdenScoped services aren't directly or indirectly injected into singletons.

Der Stammdienstanbieter wird erstellt, wenn BuildServiceProvider aufgerufen wird.The root service provider is created when BuildServiceProvider is called. Die Lebensdauer des Stammdienstanbieters entspricht der Lebensdauer der App/des Servers, wenn der Anbieter mit der App erstellt wird und verworfen wird, wenn die App beendet wird.The root service provider's lifetime corresponds to the app/server's lifetime when the provider starts with the app and is disposed when the app shuts down.

Bereichsbezogene Dienste werden von dem Container verworfen, der sie erstellt hat.Scoped services are disposed by the container that created them. Wenn ein bereichsbezogener Dienst im Stammcontainer erstellt wird, wird die Lebensdauer effektiv auf Singleton heraufgestuft, da er nur vom Stammcontainer verworfen wird, wenn die App/der Server heruntergefahren wird.If a scoped service is created in the root container, the service's lifetime is effectively promoted to singleton because it's only disposed by the root container when app/server is shut down. Die Überprüfung bereichsbezogener Dienste erfasst diese Situationen, wenn BuildServiceProvider aufgerufen wird.Validating service scopes catches these situations when BuildServiceProvider is called.

Weitere Informationen finden Sie unter ASP.NET Core-Webhost.For more information, see ASP.NET Core-Webhost.

Anfordern von DienstenRequest Services

Die Dienste, die innerhalb einer ASP.NET Core-Anforderung von HttpContext verfügbar sind, werden über die HttpContext.RequestService-Sammlung verfügbar gemacht.The services available within an ASP.NET Core request from HttpContext are exposed through the HttpContext.RequestServices collection.

Anforderungsdienste stellen die Dienste dar, die als Teil der App konfiguriert und angefordert werden.Request Services represent the services configured and requested as part of the app. Wenn Objekte Abhängigkeiten angeben, werden diese von den in RequestServices gefundenen Typen erfüllt (nicht in ApplicationServices).When the objects specify dependencies, these are satisfied by the types found in RequestServices, not ApplicationServices.

Generell sollte die App diese Eigenschaften nicht direkt verwenden.Generally, the app shouldn't use these properties directly. Fordern Sie stattdessen die von Klassen benötigten Typen über Klassenkonstruktoren an, und lassen Sie das Framework die Abhängigkeiten einfügen.Instead, request the types that classes require via class constructors and allow the framework inject the dependencies. So erhalten Sie Klassen, die einfacher getestet werden können.This yields classes that are easier to test.

Hinweis

Fordern Sie für den Zugriff auf die RequestServices-Sammlung Abhängigkeiten lieber als Konstruktorparameter an.Prefer requesting dependencies as constructor parameters to accessing the RequestServices collection.

Entwerfen von Diensten für die AbhängigkeitsinjektionDesign services for dependency injection

Best Practices:Best practices are to:

  • Entwerfen Sie Dienste zur Verwendung der Abhängigkeitsinjektion, um ihre Abhängigkeiten zu erhalten.Design services to use dependency injection to obtain their dependencies.
  • Vermeiden Sie zustandsbehaftete statische Klassen und Member.Avoid stateful, static classes and members. Entwerfen Sie Apps so, dass stattdessen Singletondienste verwendet werden. Diese vermeiden das Entstehen eines globalen Zustands.Design apps to use singleton services instead, which avoid creating global state.
  • Vermeiden Sie die direkte Instanziierung abhängiger Klassen innerhalb von Diensten.Avoid direct instantiation of dependent classes within services. Die direkte Instanziierung koppelt den Code an eine bestimmte Implementierung.Direct instantiation couples the code to a particular implementation.
  • Erstellen Sie kleine, gut gestaltete und einfach zu testende Apps.Make app classes small, well-factored, and easily tested.

Wenn eine Klasse zu viele eingefügte Abhängigkeiten zu haben scheint, ist dies im Allgemeinen ein Zeichen dafür, dass die Klasse zu viele Aufgaben hat und gegen das Single-Responsibility-Prinzip (SRP) (Prinzip der eindeutigen Verantwortlichkeit) verstößt.If a class seems to have too many injected dependencies, this is generally a sign that the class has too many responsibilities and is violating the Single Responsibility Principle (SRP). Versuchen Sie, die Klasse umzugestalten, indem Sie einige ihrer Aufgaben in eine neue Klasse verschieben.Attempt to refactor the class by moving some of its responsibilities into a new class. Beachten Sie, dass der Fokus der Razor Pages-Seitenmodellklassen und MVC-Controllerklassen auf der Benutzeroberfläche liegt.Keep in mind that Razor Pages page model classes and MVC controller classes should focus on UI concerns. Geschäftsregeln und Implementierungsdetails für den Datenzugriff sollten in Klassen aufbewahrt werden gemäß dem Prinzip Separation of Concerns (Trennung der Zuständigkeiten).Business rules and data access implementation details should be kept in classes appropriate to these separate concerns.

Löschen von DienstenDisposal of services

Der Container ruft Dispose für die erstellten IDisposable-Typen auf.The container calls Dispose for the IDisposable types it creates. Wenn eine Instanz dem Container per Benutzercode hinzugefügt wird, wird sie nicht automatisch gelöscht.If an instance is added to the container by user code, it isn't disposed automatically.

Im folgenden Beispiel werden die Dienste vom Dienstcontainer erstellt und automatisch verworfen:In the following example, the services are created by the service container and disposed automatically:

public class Service1 : IDisposable {}
public class Service2 : IDisposable {}

public interface IService3 {}
public class Service3 : IService3, IDisposable {}

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<Service1>();
    services.AddSingleton<Service2>();
    services.AddSingleton<IService3>(sp => new Service3());
}

Im folgenden Beispiel:In the following example:

  • werden die Dienstinstanzen nicht vom Dienstcontainer erstellt.The service instances aren't created by the service container.
  • kennt das Framework die geplante Lebensdauer der Dienste nicht.The intended service lifetimes aren't known by the framework.
  • verwirft das Framework die Dienste nicht automatisch.The framework doesn't dispose of the services automatically.
  • werden Dienste, die nicht explizit im Entwicklercode verworfen werden, weiter ausgeführt, bis die App beendet wird.If the services aren't explicitly disposed in developer code, they persist until the app shuts down.
public class Service1 : IDisposable {}
public class Service2 : IDisposable {}

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<Service1>(new Service1());
    services.AddSingleton(new Service2());
}

IDisposable-Anleitung für vorübergehende and freigegebene InstanzenIDisposable guidance for Transient and shared instances

Vorübergehende, eingeschränkte LebensdauerTransient, limited lifetime

SzenarioScenario

Für die App ist eine IDisposable-Instanz mit einer vorübergehenden Lebensdauer für eines der folgenden Szenarios erforderlich:The app requires an IDisposable instance with a transient lifetime for either of the following scenarios:

  • Die-Instanz wird im Stammbereich aufgelöst.The instance is resolved in the root scope.
  • Die Instanz sollte verworfen werden, bevor der Bereich endet.The instance should be disposed before the scope ends.

LösungSolution

Verwenden Sie das Factorymuster, um eine Instanz außerhalb des übergeordneten Bereichs zu erstellen.Use the factory pattern to create an instance outside of the parent scope. In dieser Situation verfügt die App in der Regel über eine Create-Methode, die den Konstruktor des endgültigen Typs direkt aufruft.In this situation, the app would generally have a Create method that calls the final type's constructor directly. Wenn der endgültige Typ andere Abhängigkeiten aufweist, kann die Factory folgende Aktionen ausführen:If the final type has other dependencies, the factory can:

Freigegebene Instanz, eingeschränkte LebensdauerShared Instance, limited lifetime

SzenarioScenario

Für die App ist eine freigegebene IDisposable-Instanz über mehrere Dienste erforderlich, die IDisposable sollte jedoch eine begrenzte Lebensdauer haben.The app requires a shared IDisposable instance across multiple services, but the IDisposable should have a limited lifetime.

LösungSolution

Registrieren Sie die Instanz mit einer bereichsbezogenen Lebensdauer.Register the instance with a Scoped lifetime. Verwenden Sie IServiceScopeFactory.CreateScope für den Start und zum Erstellen einer neuen IServiceScope.Use IServiceScopeFactory.CreateScope to start and create a new IServiceScope. Verwenden Sie die IServiceProvider-Schnittstelle des Bereichs, um die erforderlichen Dienste abzurufen.Use the scope's IServiceProvider to get required services. Löschen Sie den Bereich, wenn die Lebensdauer beendet werden soll.Dispose the scope when the lifetime should end.

Allgemeine RichtlinienGeneral Guidelines

  • Registrieren Sie keine IDisposable-Instanzen mit einem vorübergehenden Gültigkeitsbereich.Don't register IDisposable instances with a Transient scope. Verwenden Sie stattdessen das Factorymuster.Use the factory pattern instead.
  • Lösen Sie keine vorübergehenden oder bereichsbezogenen IDisposable-Instanzen im Stammbereich auf.Don't resolve Transient or Scoped IDisposable instances in the root scope. Die einzige allgemeine Ausnahme gilt, wenn die App die IServiceProvider-Instanz erstellt bzw. erneut erstellt und freigibt, was kein ideales Muster ist.The only general exception is when the app creates/recreates and disposes the IServiceProvider, which isn't an ideal pattern.
  • Wenn eine IDisposable-Abhängigkeit über DI empfangen wird, ist es nicht erforderlich, dass der Empfänger IDisposable selbst implementiert.Receiving an IDisposable dependency via DI doesn't require that the receiver implement IDisposable itself. Der Empfänger der IDisposable-Abhängigkeit darf Dispose auf dieser Abhängigkeit nicht abrufen.The receiver of the IDisposable dependency shouldn't call Dispose on that dependency.
  • Bereiche sollten verwendet werden, um die Lebensdauer von Diensten zu steuern.Scopes should be used to control lifetimes of services. Bereiche sind nicht hierarchisch, und es gibt keine besondere Verbindung zwischen den Bereichen.Scopes aren't hierarchical, and there's no special connection among scopes.

Ersetzen von StandarddienstcontainernDefault service container replacement

Der integrierte Dienstcontainer dient dazu, die Anforderungen des Frameworks und der meisten Consumer-Apps zu erfüllen.The built-in service container is designed to serve the needs of the framework and most consumer apps. Die Verwendung des integrierten Containers wird empfohlen, es sei denn, Sie benötigen ein bestimmtes Feature, das von diesem nicht unterstützt wird. Einige Beispiele:We recommend using the built-in container unless you need a specific feature that the built-in container doesn't support, such as:

  • EigenschaftsinjektionProperty injection
  • Auf Namen basierende InjektionInjection based on name
  • Untergeordnete ContainerChild containers
  • Benutzerdefinierte Verwaltung der LebensdauerCustom lifetime management
  • Func<T>-Unterstützung für die verzögerte InitialisierungFunc<T> support for lazy initialization
  • Konventionsbasierte RegistrierungConvention-based registration

Die folgenden Container von Drittanbietern können mit ASP.NET Core-Apps verwendet werden:The following third-party containers can be used with ASP.NET Core apps:

ThreadsicherheitThread safety

Erstellen Sie threadsichere Singleton-Dienste.Create thread-safe singleton services. Wenn ein Singleton-Dienst eine Abhängigkeit von einem vorübergehenden Dienst aufweist, muss der vorübergehende Dienst abhängig von der Verwendungsweise durch das Singleton ebenfalls threadsicher sein.If a singleton service has a dependency on a transient service, the transient service may also require thread safety depending how it's used by the singleton.

Die Factorymethode des einzelnen Diensts, z. B. das zweite Argument für AddSingleton<TService>(IServiceCollection, Func<IServiceProvider,TService>), muss nicht threadsicher sein.The factory method of single service, such as the second argument to AddSingleton<TService>(IServiceCollection, Func<IServiceProvider,TService>), doesn't need to be thread-safe. Wie bei static-Konstruktoren erfolgt der Aufruf einmalig über einen einzelnen Thread.Like a type (static) constructor, it's guaranteed to be called once by a single thread.

EmpfehlungenRecommendations

  • async/await- und Task-basierte Dienstauflösung wird nicht unterstützt.async/await and Task based service resolution is not supported. C# unterstützt keine asynchronen Konstruktoren. Daher wird empfohlen, asynchrone Methoden zu verwenden, nachdem der Dienst synchron aufgelöst wurde.C# does not support asynchronous constructors; therefore, the recommended pattern is to use asynchronous methods after synchronously resolving the service.

  • Vermeiden Sie das Speichern von Daten und die direkte Konfiguration im Dienstcontainer.Avoid storing data and configuration directly in the service container. Der Einkaufswagen eines Benutzers sollte z. B. normalerweise nicht dem Dienstcontainer hinzugefügt werden.For example, a user's shopping cart shouldn't typically be added to the service container. Bei der Konfiguration sollte das Optionsmuster verwendet werden.Configuration should use the options pattern. Gleichermaßen sollten Sie „Datencontainer“-Objekte vermeiden, die nur vorhanden sind, um den Zugriff auf einige andere Objekte zuzulassen.Similarly, avoid "data holder" objects that only exist to allow access to some other object. Das tatsächlich benötige Element sollte besser über Dependency Injection angefordert werden.It's better to request the actual item via DI.

  • Vermeiden Sie statischen Zugriff auf Dienste.Avoid static access to services. Vermeiden Sie statische Eingabe von IApplicationBuilder.ApplicationServices zur Verwendung an anderer Stelle.For example, avoid statically-typing IApplicationBuilder.ApplicationServices for use elsewhere.

  • Vermeiden Sie die Verwendung des Dienstlocatormusters, da dieses Steuerungsumkehrungsstrategien vermischt.Avoid using the service locator pattern, which mixes Inversion of Control strategies.

    • Rufen Sie beispielsweise nicht GetService auf, um eine Dienstinstanz zu erhalten, wenn Sie stattdessen Abhängigkeitsinjektion verwenden können:Don't invoke GetService to obtain a service instance when you can use DI instead:

      Falsch:Incorrect:

      public class MyClass()
      
        public void MyMethod()
        {
            var optionsMonitor = 
                _services.GetService<IOptionsMonitor<MyOptions>>();
            var option = optionsMonitor.CurrentValue.Option;
      
            ...
        }
      

      Richtig:Correct:

      public class MyClass
      {
          private readonly IOptionsMonitor<MyOptions> _optionsMonitor;
      
          public MyClass(IOptionsMonitor<MyOptions> optionsMonitor)
          {
              _optionsMonitor = optionsMonitor;
          }
      
          public void MyMethod()
          {
              var option = _optionsMonitor.CurrentValue.Option;
      
              ...
          }
      }
      
  • Vermeiden Sie die Injektion von Factorys, die Abhängigkeiten zur Laufzeit mit GetService auflösen.Avoid injecting a factory that resolves dependencies at runtime using GetService.

  • Vermeiden Sie den statischen Zugriff auf HttpContext (z. B. IHttpContextAccessor.HttpContext).Avoid static access to HttpContext (for example, IHttpContextAccessor.HttpContext).

Wie bei allen Empfehlungen treffen Sie möglicherweise auf Situationen, in denen eine Empfehlung ignoriert werden muss.Like all sets of recommendations, you may encounter situations where ignoring a recommendation is required. Es gibt nur wenige Ausnahmen, die sich meistens auf besondere Fälle innerhalb des Frameworks beziehen.Exceptions are rare, mostly special cases within the framework itself.

Dependency Injection stellt eine Alternative zu statischen bzw. globalen Objektzugriffsmustern dar.DI is an alternative to static/global object access patterns. Sie werden keinen Nutzen aus der Dependency Injection ziehen können, wenn Sie diese mit dem Zugriff auf statische Objekte kombinieren.You may not be able to realize the benefits of DI if you mix it with static object access.

Zusätzliche RessourcenAdditional resources