Optionsmuster in ASP.NET CoreOptions pattern in ASP.NET Core

Von Kirk Larkin und Rick AndersonBy Kirk Larkin and Rick Anderson.

Das Optionsmuster verwendet Klassen, um stark typisierten Zugriff auf zusammengehörige Einstellungsgruppen zu ermöglichen.The options pattern uses classes to provide strongly typed access to groups of related settings. Wenn Konfigurationseinstellungen nach Szenario in separate Klassen isoliert werden, entspricht die Anwendung zwei wichtigen Prinzipien der Softwareentwicklung:When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

Optionen bieten auch einen Mechanismus, um Konfigurationsdaten zu validieren.Options also provide a mechanism to validate configuration data. Weitere Informationen finden Sie im Abschnitt Optionsvalidierung.For more information, see the Options validation section.

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

Binden von hierarchischen KonfigurationsdatenBind hierarchical configuration

Die bevorzugte Methode für das Lesen zugehöriger Konfigurationswerte ist die Verwendung des Optionsmusters.The preferred way to read related configuration values is using the options pattern. Um z. B. die folgenden Konfigurationswerte zu lesen:For example, to read the following configuration values:

  "Position": {
    "Title": "Editor",
    "Name": "Joe Smith"
  }

Erstellen Sie die folgende neue PositionOptions-Klasse:Create the following PositionOptions class:

public class PositionOptions
{
    public const string Position = "Position";

    public string Title { get; set; }
    public string Name { get; set; }
}

Eine Optionsklasse:An options class:

  • Eine Optionsklasse muss nicht abstrakt sein und über einen öffentlichen parameterlosen Konstruktor verfügen.Must be non-abstract with a public parameterless constructor.
  • Alle öffentlichen Lese-/Schreibeigenschaften des Typs sind gebunden.All public read-write properties of the type are bound.
  • Felder werden nicht gebunden.Fields are not bound. Im vorangehenden Code ist Position nicht gebunden.In the preceding code, Position is not bound. Die Position-Eigenschaft wird verwendet, sodass die Zeichenfolge "Position" nicht in der App hartcodiert werden muss, wenn die Klasse an einen Konfigurationsanbieter gebunden wird.The Position property is used so the string "Position" doesn't need to be hard coded in the app when binding the class to a configuration provider.

Der folgende CodeThe following code:

  • Ruft ConfigurationBinder.Bind auf, um die PositionOptions-Klasse an den Position-Abschnitt zu binden.Calls ConfigurationBinder.Bind to bind the PositionOptions class to the Position section.
  • Zeigt die Position-Konfigurationsdaten an.Displays the Position configuration data.
public class Test22Model : PageModel
{
    private readonly IConfiguration Configuration;

    public Test22Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {
        var positionOptions = new PositionOptions();
        Configuration.GetSection(PositionOptions.Position).Bind(positionOptions);

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Im vorangehenden Code werden standardmäßig Änderungen an der JSON-Konfigurationsdatei gelesen, nachdem die App gestartet wurde.In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

ConfigurationBinder.Get<T> bindet den angegebenen Typ und gibt ihn zurück.ConfigurationBinder.Get<T> binds and returns the specified type. ConfigurationBinder.Get<T> ist möglicherweise praktischer als die Verwendung von ConfigurationBinder.Bind.ConfigurationBinder.Get<T> may be more convenient than using ConfigurationBinder.Bind. Der folgende Code zeigt die Verwendung von ConfigurationBinder.Get<T> mit der PositionOptions-Klasse:The following code shows how to use ConfigurationBinder.Get<T> with the PositionOptions class:

public class Test21Model : PageModel
{
    private readonly IConfiguration Configuration;
    public PositionOptions positionOptions { get; private set; }

    public Test21Model(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public ContentResult OnGet()
    {            
        positionOptions = Configuration.GetSection(PositionOptions.Position)
                                                     .Get<PositionOptions>();

        return Content($"Title: {positionOptions.Title} \n" +
                       $"Name: {positionOptions.Name}");
    }
}

Im vorangehenden Code werden standardmäßig Änderungen an der JSON-Konfigurationsdatei gelesen, nachdem die App gestartet wurde.In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

Eine alternative Vorgehensweise bei der Verwendung des Optionsmusters besteht darin, den Position-Abschnitt zu binden und ihn zum Dependency-Injection-Dienstcontainer hinzuzufügen.An alternative approach when using the options pattern is to bind the Position section and add it to the dependency injection service container. Im folgenden Code wird PositionOptions mit Configure zum Dienstcontainer hinzugefügt und an die Konfiguration gebunden:In the following code, PositionOptions is added to the service container with Configure and bound to configuration:

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

Mithilfe des vorangehenden Codes liest der folgende Code die Positionsoptionen:Using the preceding code, the following code reads the position options:

public class Test2Model : PageModel
{
    private readonly PositionOptions _options;

    public Test2Model(IOptions<PositionOptions> options)
    {
        _options = options.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Title: {_options.Title} \n" +
                       $"Name: {_options.Name}");
    }
}

Im vorangehenden Code werden Änderungen an der JSON-Konfigurationsdatei nach dem Start der App nicht gelesen.In the preceding code, changes to the JSON configuration file after the app has started are not read. Verwenden Sie IOptionsSnapshot, um Änderungen lesen zu können, nachdem die App gestartet wurde.To read changes after the app has started, use IOptionsSnapshot.

OptionenschnittstellenOptions interfaces

IOptions<TOptions>:IOptions<TOptions>:

IOptionsSnapshot<TOptions>:IOptionsSnapshot<TOptions>:

IOptionsMonitor<TOptions>:IOptionsMonitor<TOptions>:

Mit Postkonfigurationsszenarios können Sie Optionen festlegen oder ändern, nachdem alle IConfigureOptions<TOptions>-Konfigurationen durchgeführt wurden.Post-configuration scenarios enable setting or changing options after all IConfigureOptions<TOptions> configuration occurs.

IOptionsFactory<TOptions> ist für das Erstellen neuer Optionsinstanzen zuständig.IOptionsFactory<TOptions> is responsible for creating new options instances. Es verfügt über eine einzelne Create-Methode.It has a single Create method. Die Standardimplementierung akzeptiert alle registrierten IConfigureOptions<TOptions> und IPostConfigureOptions<TOptions> und führt alle Konfigurationen zuerst und die Postkonfigurationen danach aus.The default implementation takes all registered IConfigureOptions<TOptions> and IPostConfigureOptions<TOptions> and runs all the configurations first, followed by the post-configuration. Es wird zwischen IConfigureNamedOptions<TOptions> und IConfigureOptions<TOptions> unterschieden, und es werden nur die entsprechenden Schnittstellen aufgerufen.It distinguishes between IConfigureNamedOptions<TOptions> and IConfigureOptions<TOptions> and only calls the appropriate interface.

IOptionsMonitorCache<TOptions> wird von IOptionsMonitor<TOptions> zum Zwischenspeichern der TOptions-Instanzen verwendet.IOptionsMonitorCache<TOptions> is used by IOptionsMonitor<TOptions> to cache TOptions instances. IOptionsMonitorCache<TOptions> erklärt Optionsinstanzen im Monitor für ungültig, sodass der Wert neu berechnet wird (TryRemove).The IOptionsMonitorCache<TOptions> invalidates options instances in the monitor so that the value is recomputed (TryRemove). Werte können manuell mit TryAdd eingeführt werden.Values can be manually introduced with TryAdd. Die Clear-Methode wird verwendet, wenn alle benannten Instanzen bei Bedarf neu erstellt werden sollen.The Clear method is used when all named instances should be recreated on demand.

Verwenden von IOptionsSnapshot zum Lesen aktualisierter DatenUse IOptionsSnapshot to read updated data

Mithilfe von IOptionsSnapshot<TOptions> werden Optionen einmal pro Anforderung berechnet. Dies geschieht, wenn auf sie zugegriffen wird und sie für die Dauer der Anforderung zwischengespeichert werden.Using IOptionsSnapshot<TOptions>, options are computed once per request when accessed and cached for the lifetime of the request. Änderungen an der Konfiguration werden gelesen, nachdem die App gestartet wurde, wenn Konfigurationsanbieter verwendet werden, die das Lesen aktualisierter Konfigurationswerte unterstützen.Changes to the configuration are read after the app starts when using configuration providers that support reading updated configuration values.

Der Unterschied zwischen IOptionsMonitor und IOptionsSnapshot ist folgender:The difference between IOptionsMonitor and IOptionsSnapshot is that:

  • IOptionsMonitor ist ein Singleton-Dienst, der zu jeder Zeit aktuelle Optionswerte empfängt, was insbesondere bei Singleton-Abhängigkeiten nützlich ist.IOptionsMonitor is a singleton service that retrieves current option values at any time, which is especially useful in singleton dependencies.
  • IOptionsSnapshot ist ein bereichsbezogener Dienst und bietet eine Momentaufnahme der Optionen zu dem Zeitpunkt, da das IOptionsSnapshot<T>-Objekt konstruiert wird.IOptionsSnapshot is a scoped service and provides a snapshot of the options at the time the IOptionsSnapshot<T> object is constructed. Momentaufnahmen von Optionen sind für die Verwendung mit vorübergehenden und bereichsbezogenen Abhängigkeiten bestimmt.Options snapshots are designed for use with transient and scoped dependencies.

Der folgende Code verwendet IOptionsSnapshot<TOptions>.The following code uses IOptionsSnapshot<TOptions>.

public class TestSnapModel : PageModel
{
    private readonly MyOptions _snapshotOptions;

    public TestSnapModel(IOptionsSnapshot<MyOptions> snapshotOptionsAccessor)
    {
        _snapshotOptions = snapshotOptionsAccessor.Value;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_snapshotOptions.Option1} \n" +
                       $"Option2: {_snapshotOptions.Option2}");
    }
}

Der folgende Code registriert eine Konfigurationsinstanz, mit der MyOptions eine Bindung herstellt:The following code registers a configuration instance which MyOptions binds against:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

Im vorangehenden Code werden Änderungen an der JSON-Konfigurationsdatei nach dem Start der App gelesen.In the preceding code, changes to the JSON configuration file after the app has started are read.

IOptionsMonitorIOptionsMonitor

Der folgende Code registriert eine Konfigurationsinstanz, mit der MyOptions eine Bindung herstellt.The following code registers a configuration instance which MyOptions binds against.

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));

    services.AddRazorPages();
}

Im folgenden Beispiel wird IOptionsMonitor<TOptions> verwendet:The following example uses IOptionsMonitor<TOptions>:

public class TestMonitorModel : PageModel
{
    private readonly IOptionsMonitor<MyOptions> _optionsDelegate;

    public TestMonitorModel(IOptionsMonitor<MyOptions> optionsDelegate )
    {
        _optionsDelegate = optionsDelegate;
    }

    public ContentResult OnGet()
    {
        return Content($"Option1: {_optionsDelegate.CurrentValue.Option1} \n" +
                       $"Option2: {_optionsDelegate.CurrentValue.Option2}");
    }
}

Im vorangehenden Code werden standardmäßig Änderungen an der JSON-Konfigurationsdatei gelesen, nachdem die App gestartet wurde.In the preceding code, by default, changes to the JSON configuration file after the app has started are read.

Unterstützung für benannte Optionen mit IConfigureNamedOptionsNamed options support using IConfigureNamedOptions

Benannte Optionen...Named options:

  • sind nützlich, wenn mehrere Konfigurationsabschnitte an die gleichen Eigenschaften gebunden werden.Are useful when multiple configuration sections bind to the same properties.
  • unterscheiden zwischen Groß-/Kleinschreibung.Are case sensitive.

Sehen Sie sich die nachfolgende Datei appsettings.json an:Consider the following appsettings.json file:

{
  "TopItem": {
    "Month": {
      "Name": "Green Widget",
      "Model": "GW46"
    },
    "Year": {
      "Name": "Orange Gadget",
      "Model": "OG35"
    }
  }
}

Anstatt zwei Klassen für die Bindung von TopItem:Month und TopItem:Year zu erstellen, wird folgende Klasse für jeden Abschnitt verwendet:Rather than creating two classes to bind TopItem:Month and TopItem:Year, the following class is used for each section:

public class TopItemSettings
{
    public const string Month = "Month";
    public const string Year = "Year";

    public string Name { get; set; }
    public string Model { get; set; }
}

Der folgende Code dient zum Konfigurieren der benannten Optionen:The following code configures the named options:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<TopItemSettings>(TopItemSettings.Month,
                                       Configuration.GetSection("TopItem:Month"));
    services.Configure<TopItemSettings>(TopItemSettings.Year,
                                        Configuration.GetSection("TopItem:Year"));

    services.AddRazorPages();
}

Der folgende Code zeigt die benannten Optionen an:The following code displays the named options:

public class TestNOModel : PageModel
{
    private readonly TopItemSettings _monthTopItem;
    private readonly TopItemSettings _yearTopItem;

    public TestNOModel(IOptionsSnapshot<TopItemSettings> namedOptionsAccessor)
    {
        _monthTopItem = namedOptionsAccessor.Get(TopItemSettings.Month);
        _yearTopItem = namedOptionsAccessor.Get(TopItemSettings.Year);
    }

    public ContentResult OnGet()
    {
        return Content($"Month:Name {_monthTopItem.Name} \n" +
                       $"Month:Model {_monthTopItem.Model} \n\n" +
                       $"Year:Name {_yearTopItem.Name} \n" +
                       $"Year:Model {_yearTopItem.Model} \n"   );
    }
}

Alle Optionen sind benannte Instanzen.All options are named instances. IConfigureOptions<TOptions>-Instanzen werden behandelt, als würden sie die Options.DefaultName-Instanz anzielen. Diese ist string.Empty.IConfigureOptions<TOptions> instances are treated as targeting the Options.DefaultName instance, which is string.Empty. IConfigureNamedOptions<TOptions> implementiert auch IConfigureOptions<TOptions>.IConfigureNamedOptions<TOptions> also implements IConfigureOptions<TOptions>. Die standardmäßige Implementierung von IOptionsFactory<TOptions> verfügt über eine Logik, um jede einzelne entsprechend zu verwenden.The default implementation of the IOptionsFactory<TOptions> has logic to use each appropriately. Die benannte Option null wird verwendet, um auf alle benannten Instanzen anstelle einer bestimmten benannten Instanz abzuzielen.The null named option is used to target all of the named instances instead of a specific named instance. ConfigureAll und PostConfigureAll verwenden diese Konvention.ConfigureAll and PostConfigureAll use this convention.

OptionsBuilder-APIOptionsBuilder API

OptionsBuilder<TOptions> dient zum Konfigurieren von TOptions-Instanzen.OptionsBuilder<TOptions> is used to configure TOptions instances. OptionsBuilder optimiert die Erstellung von benannten Optionen, da es sich nur um einen einzelnen Parameter für den ersten AddOptions<TOptions>(string optionsName)-Aufruf handelt statt um alle nachfolgenden Aufrufe.OptionsBuilder streamlines creating named options as it's only a single parameter to the initial AddOptions<TOptions>(string optionsName) call instead of appearing in all of the subsequent calls. Die Optionsvalidierung und die ConfigureOptions-Überladungen, die Dienstabhängigkeiten akzeptieren, sind nur über OptionsBuilder verfügbar.Options validation and the ConfigureOptions overloads that accept service dependencies are only available via OptionsBuilder.

OptionsBuilder wird im Abschnitt Überprüfung von Optionen verwendet.OptionsBuilder is used in the Options validation section.

Verwenden von DI-Diensten zum Konfigurieren von OptionenUse DI services to configure options

Der Zugriff auf Dienste ist über die Dependency Injection möglich, während Optionen auf zwei Arten konfiguriert werden:Services can be accessed from dependency injection while configuring options in two ways:

Es empfiehlt sich das Übergeben eines Konfigurationsdelegaten an Konfigurieren, da das Erstellen eines Diensts etwas komplexer ist.We recommend passing a configuration delegate to Configure, since creating a service is more complex. Das Erstellen eines Typs entspricht den Aktionen des Frameworks beim Aufruf von Configure.Creating a type is equivalent to what the framework does when calling Configure. Wenn Konfigurieren aufgerufen wird, wird eine vorübergehende, generische IConfigureNamedOptions<TOptions> registriert, die über einen Konstruktor verfügt, der die angegeben generischen Diensttypen akzeptiert.Calling Configure registers a transient generic IConfigureNamedOptions<TOptions>, which has a constructor that accepts the generic service types specified.

Überprüfung von OptionenOptions validation

Bei der Überprüfung der Optionen können Optionswerte überprüft werden.Options validation enables option values to be validated.

Sehen Sie sich die nachfolgende Datei appsettings.json an:Consider the following appsettings.json file:

{
  "MyConfig": {
    "Key1": "My Key One",
    "Key2": 10,
    "Key3": 32
  }
}

Die folgende Klasse erstellt eine Bindung zum "MyConfig"-Konfigurationsabschnitt und wendet einige DataAnnotations-Regeln an:The following class binds to the "MyConfig" configuration section and applies a couple of DataAnnotations rules:

public class MyConfigOptions
{
    public const string MyConfig = "MyConfig";

    [RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
    public string Key1 { get; set; }
    [Range(0, 1000,
        ErrorMessage = "Value for {0} must be between {1} and {2}.")]
    public int Key2 { get; set; }
    public int Key3 { get; set; }
}

Der folgende CodeThe following code:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddOptions<MyConfigOptions>()
            .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
            .ValidateDataAnnotations();

        services.AddControllersWithViews();
    }

Die ValidateDataAnnotations-Erweiterungsmethode wird im NuGet-Paket Microsoft.Extensions.Options.DataAnnotations definiert.The ValidateDataAnnotations extension method is defined in the Microsoft.Extensions.Options.DataAnnotations NuGet package. Für Web-Apps, die das Microsoft.NET.Sdk.Web SDK verwenden, wird auf dieses Paket implizit über das geteilte Framework verwiesen.For web apps that use the Microsoft.NET.Sdk.Web SDK, this package is referenced implicitly from the shared framework.

Der folgende Code zeigt die Konfigurationswerte oder die Überprüfungsfehler an:The following code displays the configuration values or the validation errors:

public class HomeController : Controller
{
    private readonly ILogger<HomeController> _logger;
    private readonly IOptions<MyConfigOptions> _config;

    public HomeController(IOptions<MyConfigOptions> config,
                          ILogger<HomeController> logger)
    {
        _config = config;
        _logger = logger;

        try
        {
            var configValue = _config.Value;
           
        }
        catch (OptionsValidationException ex)
        {
            foreach (var failure in ex.Failures)
            {
                _logger.LogError(failure);
            }
        }
    }

    public ContentResult Index()
    {
        string msg;
        try
        {
             msg = $"Key1: {_config.Value.Key1} \n" +
                   $"Key2: {_config.Value.Key2} \n" +
                   $"Key3: {_config.Value.Key3}";
        }
        catch (OptionsValidationException optValEx)
        {
            return Content(optValEx.Message);
        }
        return Content(msg);
    }

Der folgende Code wendet mithilfe eines Delegaten eine komplexere Überprüfungsregel an:The following code applies a more complex validation rule using a delegate:

public void ConfigureServices(IServiceCollection services)
{
    services.AddOptions<MyConfigOptions>()
        .Bind(Configuration.GetSection(MyConfigOptions.MyConfig))
        .ValidateDataAnnotations()
        .Validate(config =>
        {
            if (config.Key2 != 0)
            {
                return config.Key3 > config.Key2;
            }

            return true;
        }, "Key3 must be > than Key2.");   // Failure message.

    services.AddControllersWithViews();
}

IValidateOptions für die komplexe ÜberprüfungIValidateOptions for complex validation

Die folgende Klasse implementiert IValidateOptions<TOptions>:The following class implements IValidateOptions<TOptions>:

public class MyConfigValidation : IValidateOptions<MyConfigOptions>
{
    public MyConfigOptions _config { get; private set; }

    public  MyConfigValidation(IConfiguration config)
    {
        _config = config.GetSection(MyConfigOptions.MyConfig)
            .Get<MyConfigOptions>();
    }

    public ValidateOptionsResult Validate(string name, MyConfigOptions options)
    {
        string vor=null;
        var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
        var match = rx.Match(options.Key1);

        if (string.IsNullOrEmpty(match.Value))
        {
            vor = $"{options.Key1} doesn't match RegEx \n";
        }

        if ( options.Key2 < 0 || options.Key2 > 1000)
        {
            vor = $"{options.Key2} doesn't match Range 0 - 1000 \n";
        }

        if (_config.Key2 != default)
        {
            if(_config.Key3 <= _config.Key2)
            {
                vor +=  "Key3 must be > than Key2.";
            }
        }

        if (vor != null)
        {
            return ValidateOptionsResult.Fail(vor);
        }

        return ValidateOptionsResult.Success;
    }
}

IValidateOptions ermöglicht das Verschieben des Überprüfungscodes aus StartUp und in eine Klasse.IValidateOptions enables moving the validation code out of StartUp and into a class.

Mit dem vorangehenden Code wird die Überprüfung in Startup.ConfigureServices aktiviert:Using the preceding code, validation is enabled in Startup.ConfigureServices with the following code:

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MyConfigOptions>(Configuration.GetSection(
                                        MyConfigOptions.MyConfig));
    services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
                              <MyConfigOptions>, MyConfigValidation>());
    services.AddControllersWithViews();
}

Optionen für die PostkonfigurationOptions post-configuration

Legen Sie die Postkonfiguration mit IPostConfigureOptions<TOptions> fest.Set post-configuration with IPostConfigureOptions<TOptions>. Die Postkonfiguration erfolgt, nachdem die gesamte IConfigureOptions<TOptions>-Konfiguration abgeschlossen ist:Post-configuration runs after all IConfigureOptions<TOptions> configuration occurs:

services.PostConfigure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

PostConfigure ist nach dem Konfigurieren der benannten Optionen verfügbar:PostConfigure is available to post-configure named options:

services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Verwenden Sie PostConfigureAll zur Postkonfiguration aller Konfigurationsinstanzen:Use PostConfigureAll to post-configure all configuration instances:

services.PostConfigureAll<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Zugreifen auf Optionen während des StartsAccessing options during startup

IOptions<TOptions> und IOptionsMonitor<TOptions> können in Startup.Configure verwendet werden, da Dienste erstellt werden, bevor die Configure-Methode ausgeführt wird.IOptions<TOptions> and IOptionsMonitor<TOptions> can be used in Startup.Configure, since services are built before the Configure method executes.

public void Configure(IApplicationBuilder app, 
    IOptionsMonitor<MyOptions> optionsAccessor)
{
    var option1 = optionsAccessor.CurrentValue.Option1;
}

Verwenden Sie IOptions<TOptions> oder IOptionsMonitor<TOptions> nicht in Startup.ConfigureServices.Don't use IOptions<TOptions> or IOptionsMonitor<TOptions> in Startup.ConfigureServices. Es kann einen inkonsistenten Optionszustand geben. Dies liegt an der Reihenfolge der Dienstregistrierungen.An inconsistent options state may exist due to the ordering of service registrations.

NuGet-Paket Options.ConfigurationExtensionsOptions.ConfigurationExtensions NuGet package

Auf das Paket Microsoft.Extensions.Options.ConfigurationExtensions wird implizit in ASP.NET Core-Apps verwiesen.The Microsoft.Extensions.Options.ConfigurationExtensions package is implicitly referenced in ASP.NET Core apps.

Das Optionsmuster verwendet Klassen, um Gruppen von zusammengehörigen Einstellungen darzustellen.The options pattern uses classes to represent groups of related settings. Wenn Konfigurationseinstellungen nach Szenario in separate Klassen isoliert werden, entspricht die Anwendung zwei wichtigen Prinzipien der Softwareentwicklung:When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

Optionen bieten auch einen Mechanismus, um Konfigurationsdaten zu validieren.Options also provide a mechanism to validate configuration data. Weitere Informationen finden Sie im Abschnitt Optionsvalidierung.For more information, see the Options validation section.

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

VoraussetzungenPrerequisites

Verweisen Sie auf das Microsoft.AspNetCore.App-Metapaket, oder fügen Sie einen Paketverweis auf das Paket Microsoft.Extensions.Options.ConfigurationExtensions hinzu.Reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Options.ConfigurationExtensions package.

OptionenschnittstellenOptions interfaces

IOptionsMonitor<TOptions> wird verwendet, um Optionen abzurufen und Benachrichtigungen über Optionen für TOptions-Instanzen zu verwalten.IOptionsMonitor<TOptions> is used to retrieve options and manage options notifications for TOptions instances. IOptionsMonitor<TOptions> unterstützt die folgenden Szenarios:IOptionsMonitor<TOptions> supports the following scenarios:

Mit Postkonfigurationsszenarien können Sie Optionen festlegen oder ändern, nachdem alle IConfigureOptions<TOptions>-Konfigurationen durchgeführt wurden.Post-configuration scenarios allow you to set or change options after all IConfigureOptions<TOptions> configuration occurs.

IOptionsFactory<TOptions> ist für das Erstellen neuer Optionsinstanzen zuständig.IOptionsFactory<TOptions> is responsible for creating new options instances. Es verfügt über eine einzelne Create-Methode.It has a single Create method. Die Standardimplementierung akzeptiert alle registrierten IConfigureOptions<TOptions> und IPostConfigureOptions<TOptions> und führt alle Konfigurationen zuerst und die Postkonfigurationen danach aus.The default implementation takes all registered IConfigureOptions<TOptions> and IPostConfigureOptions<TOptions> and runs all the configurations first, followed by the post-configuration. Es wird zwischen IConfigureNamedOptions<TOptions> und IConfigureOptions<TOptions> unterschieden, und es werden nur die entsprechenden Schnittstellen aufgerufen.It distinguishes between IConfigureNamedOptions<TOptions> and IConfigureOptions<TOptions> and only calls the appropriate interface.

IOptionsMonitorCache<TOptions> wird von IOptionsMonitor<TOptions> zum Zwischenspeichern der TOptions-Instanzen verwendet.IOptionsMonitorCache<TOptions> is used by IOptionsMonitor<TOptions> to cache TOptions instances. IOptionsMonitorCache<TOptions> erklärt Optionsinstanzen im Monitor für ungültig, sodass der Wert neu berechnet wird (TryRemove).The IOptionsMonitorCache<TOptions> invalidates options instances in the monitor so that the value is recomputed (TryRemove). Werte können manuell mit TryAdd eingeführt werden.Values can be manually introduced with TryAdd. Die Clear-Methode wird verwendet, wenn alle benannten Instanzen bei Bedarf neu erstellt werden sollen.The Clear method is used when all named instances should be recreated on demand.

IOptionsSnapshot<TOptions> ist nützlich in Szenarien, in denen Optionen bei jeder Anforderung neu berechnet werden sollten.IOptionsSnapshot<TOptions> is useful in scenarios where options should be recomputed on every request. Weitere Informationen finden Sie im Abschnitt Neuladen der Konfigurationsdaten mit IOptionsSnapshot.For more information, see the Reload configuration data with IOptionsSnapshot section.

IOptions<TOptions> kann zum Unterstützen von Optionen verwendet werden.IOptions<TOptions> can be used to support options. Allerdings unterstützt IOptions<TOptions> nicht die oben beschriebenen Szenarios von IOptionsMonitor<TOptions>.However, IOptions<TOptions> doesn't support the preceding scenarios of IOptionsMonitor<TOptions>. Sie können IOptions<TOptions> weiterhin in bestehenden Frameworks und Bibliotheken verwenden, die bereits die IOptions<TOptions>-Schnittstelle verwenden und nicht die von IOptionsMonitor<TOptions> bereitgestellten Szenarios benötigen.You may continue to use IOptions<TOptions> in existing frameworks and libraries that already use the IOptions<TOptions> interface and don't require the scenarios provided by IOptionsMonitor<TOptions>.

Allgemeine OptionskonfigurationGeneral options configuration

Die allgemeine Optionskonfiguration wird als Beispiel 1 in der Beispiel-App veranschaulicht.General options configuration is demonstrated as Example 1 in the sample app.

Eine Optionsklasse muss nicht abstrakt sein und über einen öffentlichen parameterlosen Konstruktor verfügen.An options class must be non-abstract with a public parameterless constructor. Die folgende Klasse MyOptions verfügt über die zwei Eigenschaften: Option1 und Option2.The following class, MyOptions, has two properties, Option1 and Option2. Das Festlegen von Standardwerten ist optional, aber der Klassenkonstruktor im folgenden Beispiel legt den Standardwert von Option1 fest.Setting default values is optional, but the class constructor in the following example sets the default value of Option1. Option2 hat den Standardwert festgelegt, indem die Eigenschaft direkt initialisiert wurde (Models/MyOptions.cs):Option2 has a default value set by initializing the property directly (Models/MyOptions.cs):

public class MyOptions
{
    public MyOptions()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

Die MyOptions-Klasse wird zum Dienstcontainer mit Configure hinzugefügt und an die Konfiguration gebunden:The MyOptions class is added to the service container with Configure and bound to configuration:

// Example #1: General configuration
// Register the Configuration instance which MyOptions binds against.
services.Configure<MyOptions>(Configuration);

Das folgende Seitenmodel verwendet konstruktorbasierte Dependency Injection mit IOptionsMonitor<TOptions>, um auf die Einstellungen zugreifen zu können (Pages/Index.cshtml.cs):The following page model uses constructor dependency injection with IOptionsMonitor<TOptions> to access the settings (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #1: Simple options
var option1 = _options.Option1;
var option2 = _options.Option2;
SimpleOptions = $"option1 = {option1}, option2 = {option2}";

Die appsettings.json-Datei des Beispiels gibt Werte für option1 und option2 an:The sample's appsettings.json file specifies values for option1 and option2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Wenn die Anwendung ausgeführt wird, gibt die OnGet-Methode des Seitenmodells eine Zeichenfolge zurück, die die Werte der Optionsklasse anzeigt:When the app is run, the page model's OnGet method returns a string showing the option class values:

option1 = value1_from_json, option2 = -1

Hinweis

Wenn Sie eine benutzerdefinierte ConfigurationBuilder-Klasse verwenden, um Konfigurationsoptionen aus einer Einstellungsdatei zu laden, bestätigen Sie, dass der Basispfad ordnungsgemäß festgelegt ist:When using a custom ConfigurationBuilder to load options configuration from a settings file, confirm that the base path is set correctly:

var configBuilder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json", optional: true);
var config = configBuilder.Build();

services.Configure<MyOptions>(config);

Sie müssen den Basispfad nicht explizit festlegen, wenn Sie Konfigurationsoptionen über CreateDefaultBuilder aus der Einstellungsdatei laden.Explicitly setting the base path isn't required when loading options configuration from the settings file via CreateDefaultBuilder.

Konfigurieren von einfachen Optionen mit einem DelegatenConfigure simple options with a delegate

Das Konfigurieren von einfachen Optionen mit einem Delegaten wird als Beispiel 2 in der Beispiel-App veranschaulicht.Configuring simple options with a delegate is demonstrated as Example 2 in the sample app.

Verwenden Sie einen Delegaten zum Festlegen von Optionswerten.Use a delegate to set options values. Die Beispielanwendung verwendet die MyOptionsWithDelegateConfig-Klasse (Models/MyOptionsWithDelegateConfig.cs):The sample app uses the MyOptionsWithDelegateConfig class (Models/MyOptionsWithDelegateConfig.cs):

public class MyOptionsWithDelegateConfig
{
    public MyOptionsWithDelegateConfig()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

Im folgenden Code wird ein zweiter IConfigureOptions<TOptions>-Dienst zum Dienstcontainer hinzugefügt.In the following code, a second IConfigureOptions<TOptions> service is added to the service container. Er verwendet einen Delegaten zum Konfigurieren der Bindung mit MyOptionsWithDelegateConfig:It uses a delegate to configure the binding with MyOptionsWithDelegateConfig:

// Example #2: Options bound and configured by a delegate
services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
{
    myOptions.Option1 = "value1_configured_by_delegate";
    myOptions.Option2 = 500;
});

Index.cshtml.cs:Index.cshtml.cs:

private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #2: Options configured by delegate
var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
SimpleOptionsWithDelegateConfig = 
    $"delegate_option1 = {delegate_config_option1}, " +
    $"delegate_option2 = {delegate_config_option2}";

Sie können mehrere Konfigurationsanbieter hinzufügen.You can add multiple configuration providers. Konfigurationsanbieter sind über NuGet-Pakete verfügbar und werden in der Reihenfolge ihrer Registrierung angewendet.Configuration providers are available from NuGet packages and are applied in the order that they're registered. Weitere Informationen finden Sie unter Konfiguration in ASP.NET Core.For more information, see Konfiguration in ASP.NET Core.

Jeder Aufruf von Configure fügt einen IConfigureOptions<TOptions>-Dienst zum Dienstcontainer hinzu.Each call to Configure adds an IConfigureOptions<TOptions> service to the service container. Im vorherigen Beispiel wurden die Werte von Option1 und Option2 beide in appsettings.json angegeben, aber die Werte von Option1 und Option2 werden vom konfigurierten Delegaten überschrieben.In the preceding example, the values of Option1 and Option2 are both specified in appsettings.json, but the values of Option1 and Option2 are overridden by the configured delegate.

Wenn mehr als ein Konfigurationsdienst aktiviert ist, gewinnt die letzte angegebene Konfigurationsquelle und legt den Konfigurationswert fest.When more than one configuration service is enabled, the last configuration source specified wins and sets the configuration value. Wenn die Anwendung ausgeführt wird, gibt die OnGet-Methode des Seitenmodells eine Zeichenfolge zurück, die die Werte der Optionsklasse anzeigt:When the app is run, the page model's OnGet method returns a string showing the option class values:

delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

Konfigurieren von UnteroptionenSuboptions configuration

Das Konfigurieren von Unteroptionen wird als Beispiel 3 in der Beispiel-App veranschaulicht.Suboptions configuration is demonstrated as Example 3 in the sample app.

Anwendungen sollten Optionsklassen erstellen, die für bestimmte Szenariogruppen (Klassen) in der Anwendung gelten.Apps should create options classes that pertain to specific scenario groups (classes) in the app. Die Komponenten der Anwendung, die Konfigurationswerte erfordern, sollten nur über Zugriff auf die Konfigurationswerte verfügen, die sie verwenden.Parts of the app that require configuration values should only have access to the configuration values that they use.

Beim Binden von Optionen zur Konfiguration ist jede Eigenschaft im Optionstyp an einen Konfigurationsschlüssel des property[:sub-property:]-Formulars gebunden.When binding options to configuration, each property in the options type is bound to a configuration key of the form property[:sub-property:]. Die MyOptions.Option1-Eigenschaft ist beispielsweise an den Schlüssel Option1 gebunden, der von der option1-Eigenschaft in appsettings.json gelesen wird.For example, the MyOptions.Option1 property is bound to the key Option1, which is read from the option1 property in appsettings.json.

Im folgenden Code wird ein dritter IConfigureOptions<TOptions>-Dienst zum Dienstcontainer hinzugefügt.In the following code, a third IConfigureOptions<TOptions> service is added to the service container. Er verbindet MySubOptions mit dem subsection-Abschnitt der appSettings.json-Datei:It binds MySubOptions to the section subsection of the appsettings.json file:

// Example #3: Suboptions
// Bind options using a sub-section of the appsettings.json file.
services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

Die GetSection-Methode erfordert den Namespace Microsoft.Extensions.Configuration.The GetSection method requires the Microsoft.Extensions.Configuration namespace.

Die appsettings.json-Datei des Beispiels definiert ein subsection-Element mit Schlüsseln für suboption1 und suboption2:The sample's appsettings.json file defines a subsection member with keys for suboption1 and suboption2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Die MySubOptions-Klasse definiert die Eigenschaften SubOption1 und SubOption2 zur Aufnahme der Optionswerte (Models/MySubOptions.cs):The MySubOptions class defines properties, SubOption1 and SubOption2, to hold the options values (Models/MySubOptions.cs):

public class MySubOptions
{
    public MySubOptions()
    {
        // Set default values.
        SubOption1 = "value1_from_ctor";
        SubOption2 = 5;
    }
    
    public string SubOption1 { get; set; }
    public int SubOption2 { get; set; }
}

Die OnGet-Methode des Seitenmodells gibt eine Zeichenfolge mit den Optionswerten (Pages/Index.cshtml.cs) zurück:The page model's OnGet method returns a string with the options values (Pages/Index.cshtml.cs):

private readonly MySubOptions _subOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #3: Suboptions
var subOption1 = _subOptions.SubOption1;
var subOption2 = _subOptions.SubOption2;
SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

Wenn die App ausgeführt wird, gibt die OnGet-Methode eine Zeichenfolge zurück, die die Werte der untergeordneten Optionsklasse anzeigt:When the app is run, the OnGet method returns a string showing the suboption class values:

subOption1 = subvalue1_from_json, subOption2 = 200

Einfügung von OptionenOptions injection

Die Einfügung von Optionen ist als Beispiel 4 in der Beispiel-App dargestellt.Options injection is demonstrated as Example 4 in the sample app.

Fügen Sie IOptionsMonitor<TOptions> ein in:Inject IOptionsMonitor<TOptions> into:

  • Eine Razor-Seite oder MVC-Ansicht mithilfe der @inject Razor-Anweisung.A Razor page or MVC view with the @inject Razor directive.
  • Ein Seiten- oder Ansichtsmodell.A page or view model.

Im folgenden Beispiel aus der Beispiel-App wird IOptionsMonitor<TOptions> in ein Seitenmodell eingefügt (Pages/Index.cshtml.cs):The following example from the sample app injects IOptionsMonitor<TOptions> into a page model (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #4: Bind options directly to the page
MyOptions = _options;

Die Beispiel-App zeigt das Einfügen von IOptionsMonitor<MyOptions> mit einer @inject-Anweisung:The sample app shows how to inject IOptionsMonitor<MyOptions> with an @inject directive:

@page
@model IndexModel
@using Microsoft.Extensions.Options
@inject IOptionsMonitor<MyOptions> OptionsAccessor
@{
    ViewData["Title"] = "Options Sample";
}

<h1>@ViewData["Title"]</h1>

Wenn die App ausgeführt wird, werden die Optionswerte in der gerenderten Seite angezeigt:When the app is run, the options values are shown in the rendered page:

Optionswerte Option1: value1_from_json und Option2: -1 werden aus dem Modell geladen und in die Ansicht eingefügt.

Neuladen der Konfigurationsdaten mit IOptionsSnapshotReload configuration data with IOptionsSnapshot

Das Neuladen der Konfigurationsdaten mit IOptionsSnapshot<TOptions> wird im Beispiel 5 in der Beispiel-App veranschaulicht.Reloading configuration data with IOptionsSnapshot<TOptions> is demonstrated in Example 5 in the sample app.

Mithilfe von IOptionsSnapshot<TOptions> werden Optionen einmal pro Anforderung berechnet. Dies geschieht, wenn auf sie zugegriffen wird und sie für die Dauer der Anforderung zwischengespeichert werden.Using IOptionsSnapshot<TOptions>, options are computed once per request when accessed and cached for the lifetime of the request.

Der Unterschied zwischen IOptionsMonitor und IOptionsSnapshot ist folgender:The difference between IOptionsMonitor and IOptionsSnapshot is that:

  • IOptionsMonitor ist ein Singleton-Dienst, der zu jeder Zeit aktuelle Optionswerte empfängt, was insbesondere bei Singleton-Abhängigkeiten nützlich ist.IOptionsMonitor is a singleton service that retrieves current option values at any time, which is especially useful in singleton dependencies.
  • IOptionsSnapshot ist ein bereichsbezogener Dienst und bietet eine Momentaufnahme der Optionen zu dem Zeitpunkt, da das IOptionsSnapshot<T>-Objekt konstruiert wird.IOptionsSnapshot is a scoped service and provides a snapshot of the options at the time the IOptionsSnapshot<T> object is constructed. Momentaufnahmen von Optionen sind für die Verwendung mit vorübergehenden und bereichsbezogenen Abhängigkeiten bestimmt.Options snapshots are designed for use with transient and scoped dependencies.

Im folgenden Beispiel wird veranschaulicht, wie eine neue IOptionsSnapshot<TOptions> nach den appsettings.json-Veränderungen erstellt wird (Pages/Index.cshtml.cs).The following example demonstrates how a new IOptionsSnapshot<TOptions> is created after appsettings.json changes (Pages/Index.cshtml.cs). Mehrere Anforderungen an den Server geben konstante Werte zurück, die von der appsettings.json-Datei bereitgestellt werden, bis die Datei geändert wird und die Konfiguration neu lädt.Multiple requests to the server return constant values provided by the appsettings.json file until the file is changed and configuration reloads.

private readonly MyOptions _snapshotOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #5: Snapshot options
var snapshotOption1 = _snapshotOptions.Option1;
var snapshotOption2 = _snapshotOptions.Option2;
SnapshotOptions = 
    $"snapshot option1 = {snapshotOption1}, " +
    $"snapshot option2 = {snapshotOption2}";

Die folgende Abbildung zeigt die anfänglichen option1- und option2-Werte, die aus der appsettings.json-Datei geladen werden:The following image shows the initial option1 and option2 values loaded from the appsettings.json file:

snapshot option1 = value1_from_json, snapshot option2 = -1

Ändern Sie die Werte in der appsettings.json-Datei auf value1_from_json UPDATED und 200.Change the values in the appsettings.json file to value1_from_json UPDATED and 200. Speichern Sie die appsettings.json-Datei.Save the appsettings.json file. Aktualisieren Sie den Browser, um festzustellen, ob die Optionswerte aktualisiert wurden:Refresh the browser to see that the options values are updated:

snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

Unterstützung für benannte Optionen mit IConfigureNamedOptionsNamed options support with IConfigureNamedOptions

Unterstützung für benannte Optionen mit IConfigureNamedOptions<TOptions> wird als Beispiel 6 in der Beispiel-App veranschaulicht.Named options support with IConfigureNamedOptions<TOptions> is demonstrated as Example 6 in the sample app.

Die Unterstützung für benannte Optionen ermöglicht es der Anwendung, zwischen den Konfigurationen benannter Optionen zu unterscheiden.Named options support allows the app to distinguish between named options configurations. In der Beispiel-App werden benannte Optionen mit OptionsServiceCollectionExtensions.Configure deklariert. Dadurch wird wiederum die Erweiterungsmethode ConfigureNamedOptions<TOptions>.Configure aufgerufen.In the sample app, named options are declared with OptionsServiceCollectionExtensions.Configure, which calls the ConfigureNamedOptions<TOptions>.Configure extension method. Benannte Optionen Unterscheidung nach Groß-/Kleinschreibung.Named options are case sensitive.

// Example #6: Named options (named_options_1)
// Register the ConfigurationBuilder instance which MyOptions binds against.
// Specify that the options loaded from configuration are named
// "named_options_1".
services.Configure<MyOptions>("named_options_1", Configuration);

// Example #6: Named options (named_options_2)
// Specify that the options loaded from the MyOptions class are named
// "named_options_2".
// Use a delegate to configure option values.
services.Configure<MyOptions>("named_options_2", myOptions =>
{
    myOptions.Option1 = "named_options_2_value1_from_action";
});

Die Beispielanwendung greift mit Get auf die benannten Optionen zu (Pages/Index.cshtml.cs):The sample app accesses the named options with Get (Pages/Index.cshtml.cs):

private readonly MyOptions _named_options_1;
private readonly MyOptions _named_options_2;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #6: Named options
var named_options_1 = 
    $"named_options_1: option1 = {_named_options_1.Option1}, " +
    $"option2 = {_named_options_1.Option2}";
var named_options_2 = 
    $"named_options_2: option1 = {_named_options_2.Option1}, " +
    $"option2 = {_named_options_2.Option2}";
NamedOptions = $"{named_options_1} {named_options_2}";

Bei der Ausführung der Beispielanwendung werden die benannten Optionen zurückgegeben:Running the sample app, the named options are returned:

named_options_1: option1 = value1_from_json, option2 = -1
named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

named_options_1-Werte werden von der Konfiguration bereitgestellt. Sie werden aus der appsettings.json-Datei geladen.named_options_1 values are provided from configuration, which are loaded from the appsettings.json file. named_options_2-Werte werden bereitgestellt vom:named_options_2 values are provided by:

  • named_options_2-Delegat in ConfigureServices für Option1.The named_options_2 delegate in ConfigureServices for Option1.
  • Der Standardwert für Option2 wird von der MyOptions-Klasse bereitgestellt.The default value for Option2 provided by the MyOptions class.

Konfigurieren aller Optionen mit der ConfigureAll-MethodeConfigure all options with the ConfigureAll method

Konfigurieren Sie alle Optionsinstanzen mit der ConfigureAll-Methode.Configure all options instances with the ConfigureAll method. Der folgende Code konfiguriert Option1 für alle Konfigurationsinstanzen mit einem gemeinsamen Wert.The following code configures Option1 for all configuration instances with a common value. Fügen Sie der Startup.ConfigureServices-Methode manuell den folgenden Code hinzu:Add the following code manually to the Startup.ConfigureServices method:

services.ConfigureAll<MyOptions>(myOptions => 
{
    myOptions.Option1 = "ConfigureAll replacement value";
});

Das Ausführen der Beispielanwendung nach dem Hinzufügen des Codes führt zu folgendem Ergebnis:Running the sample app after adding the code produces the following result:

named_options_1: option1 = ConfigureAll replacement value, option2 = -1
named_options_2: option1 = ConfigureAll replacement value, option2 = 5

Hinweis

Alle Optionen sind benannte Instanzen.All options are named instances. Vorhandene IConfigureOptions<TOptions>-Instanzen werden behandelt, als ob sie auf die Options.DefaultName-Instanz abzielen. Diese ist string.Empty.Existing IConfigureOptions<TOptions> instances are treated as targeting the Options.DefaultName instance, which is string.Empty. IConfigureNamedOptions<TOptions> implementiert auch IConfigureOptions<TOptions>.IConfigureNamedOptions<TOptions> also implements IConfigureOptions<TOptions>. Die standardmäßige Implementierung von IOptionsFactory<TOptions> verfügt über eine Logik, um jede einzelne entsprechend zu verwenden.The default implementation of the IOptionsFactory<TOptions> has logic to use each appropriately. Die benannte Option null wird verwendet, um auf alle benannten Instanzen anstelle einer bestimmten benannten Instanz abzuzielen (ConfigureAll und PostConfigureAll verwenden diese Konvention).The null named option is used to target all of the named instances instead of a specific named instance (ConfigureAll and PostConfigureAll use this convention).

OptionsBuilder-APIOptionsBuilder API

OptionsBuilder<TOptions> dient zum Konfigurieren von TOptions-Instanzen.OptionsBuilder<TOptions> is used to configure TOptions instances. OptionsBuilder optimiert die Erstellung von benannten Optionen, da es sich nur um einen einzelnen Parameter für den ersten AddOptions<TOptions>(string optionsName)-Aufruf handelt statt um alle nachfolgenden Aufrufe.OptionsBuilder streamlines creating named options as it's only a single parameter to the initial AddOptions<TOptions>(string optionsName) call instead of appearing in all of the subsequent calls. Die Optionsvalidierung und die ConfigureOptions-Überladungen, die Dienstabhängigkeiten akzeptieren, sind nur über OptionsBuilder verfügbar.Options validation and the ConfigureOptions overloads that accept service dependencies are only available via OptionsBuilder.

// Options.DefaultName = "" is used.
services.AddOptions<MyOptions>().Configure(o => o.Property = "default");

services.AddOptions<MyOptions>("optionalName")
    .Configure(o => o.Property = "named");

Verwenden von DI-Diensten zum Konfigurieren von OptionenUse DI services to configure options

Beim Konfigurieren von Optionen haben Sie zwei Möglichkeiten, auf andere Dienste aus Dependency Injections zuzugreifen:You can access other services from dependency injection while configuring options in two ways:

Es empfiehlt sich das Übergeben eines Konfigurationsdelegaten an Konfigurieren, da das Erstellen eines Diensts etwas komplexer ist.We recommend passing a configuration delegate to Configure, since creating a service is more complex. Selbst einen eigenen Typ zu erstellen ist gleichbedeutend mit dem, was das Framework für Sie übernimmt, wenn Sie Konfigurieren verwenden.Creating your own type is equivalent to what the framework does for you when you use Configure. Wenn Konfigurieren aufgerufen wird, wird eine vorübergehende, generische IConfigureNamedOptions<TOptions> registriert, die über einen Konstruktor verfügt, der die angegeben generischen Diensttypen akzeptiert.Calling Configure registers a transient generic IConfigureNamedOptions<TOptions>, which has a constructor that accepts the generic service types specified.

Überprüfung von OptionenOptions validation

Sie können Optionen überprüfen, wenn diese konfiguriert werden.Options validation allows you to validate options when options are configured. Rufen Sie Validate mit einer Überprüfungsmethode auf, die true zurückgibt, wenn die Optionen gültig sind, und false zurückgibt, wenn sie es nicht sind:Call Validate with a validation method that returns true if options are valid and false if they aren't valid:

// Registration
services.AddOptions<MyOptions>("optionalOptionsName")
    .Configure(o => { }) // Configure the options
    .Validate(o => YourValidationShouldReturnTrueIfValid(o), 
        "custom error");

// Consumption
var monitor = services.BuildServiceProvider()
    .GetService<IOptionsMonitor<MyOptions>>();

try
{
    var options = monitor.Get("optionalOptionsName");
}
catch (OptionsValidationException e) 
{
   // e.OptionsName returns "optionalOptionsName"
   // e.OptionsType returns typeof(MyOptions)
   // e.Failures returns a list of errors, which would contain 
   //     "custom error"
}

Im vorherigen Beispiel wurde die benannte Optionsinstanz auf optionalOptionsName festgelegt.The preceding example sets the named options instance to optionalOptionsName. Die Standardoptionsinstanz ist Options.DefaultName.The default options instance is Options.DefaultName.

Überprüfungen werden ausgeführt, wenn die Optionsinstanz erstellt wird.Validation runs when the options instance is created. Eine Optionsinstanz besteht die Überprüfung beim ersten Zugriff garantiert.An options instance is guaranteed to pass validation the first time it's accessed.

Wichtig

Die Überprüfung von Optionen schützt nicht vor Änderungen an Optionen nach der Erstellung der Optionsinstanz.Options validation doesn't guard against options modifications after the options instance is created. Beispielsweise werden IOptionsSnapshot-Optionen einmal pro Anforderung erstellt und überprüft, wenn zum ersten Mal auf die Optionen zugegriffen wird.For example, IOptionsSnapshot options are created and validated once per request when the options are first accessed. Die IOptionsSnapshot-Optionen werden bei nachfolgenden Zugriffsversuchen für dieselbe Anforderung nicht erneut überprüft.The IOptionsSnapshot options aren't validated again on subsequent access attempts for the same request.

Die Validate-Methode akzeptiert ein Func<TOptions, bool>-Element.The Validate method accepts a Func<TOptions, bool>. Um die Überprüfung vollständig anzupassen, implementieren Sie IValidateOptions<TOptions>. Dies ermöglicht Folgendes:To fully customize validation, implement IValidateOptions<TOptions>, which allows:

  • Eine Überprüfung von mehreren Optionstypen: class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>Validation of multiple options types: class ValidateTwo : IValidateOptions<Option1>, IValidationOptions<Option2>
  • Eine Überprüfung, die von einem anderen Optionstyp abhängig ist: public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)Validation that depends on another option type: public DependsOnAnotherOptionValidator(IOptionsMonitor<AnotherOption> options)

IValidateOptions validiert Folgendes:IValidateOptions validates:

  • Eine bestimmte benannte Optionsinstanz.A specific named options instance.
  • Alle Optionen, wenn name den Wert null aufweist.All options when name is null.

Geben Sie ein ValidateOptionsResult aus Ihrer Implementierung der Schnittstelle zurück:Return a ValidateOptionsResult from your implementation of the interface:

public interface IValidateOptions<TOptions> where TOptions : class
{
    ValidateOptionsResult Validate(string name, TOptions options);
}

Die Überprüfung auf Basis von Datenanmerkungen ist über das Paket Microsoft.Extensions.Options.DataAnnotations durch Aufrufen der ValidateDataAnnotations-Methode in OptionsBuilder<TOptions> verfügbar.Data Annotation-based validation is available from the Microsoft.Extensions.Options.DataAnnotations package by calling the ValidateDataAnnotations method on OptionsBuilder<TOptions>. Microsoft.Extensions.Options.DataAnnotations ist im Microsoft.AspNetCore.App-Metapaket enthalten.Microsoft.Extensions.Options.DataAnnotations is included in the Microsoft.AspNetCore.App metapackage.

using Microsoft.Extensions.DependencyInjection;

private class AnnotatedOptions
{
    [Required]
    public string Required { get; set; }

    [StringLength(5, ErrorMessage = "Too long.")]
    public string StringLength { get; set; }

    [Range(-5, 5, ErrorMessage = "Out of range.")]
    public int IntRange { get; set; }
}

[Fact]
public void CanValidateDataAnnotations()
{
    var services = new ServiceCollection();
    services.AddOptions<AnnotatedOptions>()
        .Configure(o =>
        {
            o.StringLength = "111111";
            o.IntRange = 10;
            o.Custom = "nowhere";
        })
        .ValidateDataAnnotations();

    var sp = services.BuildServiceProvider();

    var error = Assert.Throws<OptionsValidationException>(() => 
        sp.GetRequiredService<IOptionsMonitor<AnnotatedOptions>>().CurrentValue);
    ValidateFailure<AnnotatedOptions>(error, Options.DefaultName, 1,
        "DataAnnotation validation failed for members Required " +
            "with the error 'The Required field is required.'.",
        "DataAnnotation validation failed for members StringLength " +
            "with the error 'Too long.'.",
        "DataAnnotation validation failed for members IntRange " +
            "with the error 'Out of range.'.");
}

Die vorzeitige Überprüfung (Fail-fast beim Start) wird für ein späteres Release in Erwägung.Eager validation (fail fast at startup) is under consideration for a future release.

Optionen für die PostkonfigurationOptions post-configuration

Legen Sie die Postkonfiguration mit IPostConfigureOptions<TOptions> fest.Set post-configuration with IPostConfigureOptions<TOptions>. Die Postkonfiguration erfolgt, nachdem die gesamte IConfigureOptions<TOptions>-Konfiguration abgeschlossen ist:Post-configuration runs after all IConfigureOptions<TOptions> configuration occurs:

services.PostConfigure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

PostConfigure ist nach dem Konfigurieren der benannten Optionen verfügbar:PostConfigure is available to post-configure named options:

services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Verwenden Sie PostConfigureAll zur Postkonfiguration aller Konfigurationsinstanzen:Use PostConfigureAll to post-configure all configuration instances:

services.PostConfigureAll<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Zugreifen auf Optionen während des StartsAccessing options during startup

IOptions<TOptions> und IOptionsMonitor<TOptions> können in Startup.Configure verwendet werden, da Dienste erstellt werden, bevor die Configure-Methode ausgeführt wird.IOptions<TOptions> and IOptionsMonitor<TOptions> can be used in Startup.Configure, since services are built before the Configure method executes.

public void Configure(IApplicationBuilder app, IOptionsMonitor<MyOptions> optionsAccessor)
{
    var option1 = optionsAccessor.CurrentValue.Option1;
}

Verwenden Sie IOptions<TOptions> oder IOptionsMonitor<TOptions> nicht in Startup.ConfigureServices.Don't use IOptions<TOptions> or IOptionsMonitor<TOptions> in Startup.ConfigureServices. Es kann einen inkonsistenten Optionszustand geben. Dies liegt an der Reihenfolge der Dienstregistrierungen.An inconsistent options state may exist due to the ordering of service registrations.

Das Optionsmuster verwendet Klassen, um Gruppen von zusammengehörigen Einstellungen darzustellen.The options pattern uses classes to represent groups of related settings. Wenn Konfigurationseinstellungen nach Szenario in separate Klassen isoliert werden, entspricht die Anwendung zwei wichtigen Prinzipien der Softwareentwicklung:When configuration settings are isolated by scenario into separate classes, the app adheres to two important software engineering principles:

Optionen bieten auch einen Mechanismus, um Konfigurationsdaten zu validieren.Options also provide a mechanism to validate configuration data. Weitere Informationen finden Sie im Abschnitt Optionsvalidierung.For more information, see the Options validation section.

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

VoraussetzungenPrerequisites

Verweisen Sie auf das Microsoft.AspNetCore.App-Metapaket, oder fügen Sie einen Paketverweis auf das Paket Microsoft.Extensions.Options.ConfigurationExtensions hinzu.Reference the Microsoft.AspNetCore.App metapackage or add a package reference to the Microsoft.Extensions.Options.ConfigurationExtensions package.

OptionenschnittstellenOptions interfaces

IOptionsMonitor<TOptions> wird verwendet, um Optionen abzurufen und Benachrichtigungen über Optionen für TOptions-Instanzen zu verwalten.IOptionsMonitor<TOptions> is used to retrieve options and manage options notifications for TOptions instances. IOptionsMonitor<TOptions> unterstützt die folgenden Szenarios:IOptionsMonitor<TOptions> supports the following scenarios:

Mit Postkonfigurationsszenarien können Sie Optionen festlegen oder ändern, nachdem alle IConfigureOptions<TOptions>-Konfigurationen durchgeführt wurden.Post-configuration scenarios allow you to set or change options after all IConfigureOptions<TOptions> configuration occurs.

IOptionsFactory<TOptions> ist für das Erstellen neuer Optionsinstanzen zuständig.IOptionsFactory<TOptions> is responsible for creating new options instances. Es verfügt über eine einzelne Create-Methode.It has a single Create method. Die Standardimplementierung akzeptiert alle registrierten IConfigureOptions<TOptions> und IPostConfigureOptions<TOptions> und führt alle Konfigurationen zuerst und die Postkonfigurationen danach aus.The default implementation takes all registered IConfigureOptions<TOptions> and IPostConfigureOptions<TOptions> and runs all the configurations first, followed by the post-configuration. Es wird zwischen IConfigureNamedOptions<TOptions> und IConfigureOptions<TOptions> unterschieden, und es werden nur die entsprechenden Schnittstellen aufgerufen.It distinguishes between IConfigureNamedOptions<TOptions> and IConfigureOptions<TOptions> and only calls the appropriate interface.

IOptionsMonitorCache<TOptions> wird von IOptionsMonitor<TOptions> zum Zwischenspeichern der TOptions-Instanzen verwendet.IOptionsMonitorCache<TOptions> is used by IOptionsMonitor<TOptions> to cache TOptions instances. IOptionsMonitorCache<TOptions> erklärt Optionsinstanzen im Monitor für ungültig, sodass der Wert neu berechnet wird (TryRemove).The IOptionsMonitorCache<TOptions> invalidates options instances in the monitor so that the value is recomputed (TryRemove). Werte können manuell mit TryAdd eingeführt werden.Values can be manually introduced with TryAdd. Die Clear-Methode wird verwendet, wenn alle benannten Instanzen bei Bedarf neu erstellt werden sollen.The Clear method is used when all named instances should be recreated on demand.

IOptionsSnapshot<TOptions> ist nützlich in Szenarien, in denen Optionen bei jeder Anforderung neu berechnet werden sollten.IOptionsSnapshot<TOptions> is useful in scenarios where options should be recomputed on every request. Weitere Informationen finden Sie im Abschnitt Neuladen der Konfigurationsdaten mit IOptionsSnapshot.For more information, see the Reload configuration data with IOptionsSnapshot section.

IOptions<TOptions> kann zum Unterstützen von Optionen verwendet werden.IOptions<TOptions> can be used to support options. Allerdings unterstützt IOptions<TOptions> nicht die oben beschriebenen Szenarios von IOptionsMonitor<TOptions>.However, IOptions<TOptions> doesn't support the preceding scenarios of IOptionsMonitor<TOptions>. Sie können IOptions<TOptions> weiterhin in bestehenden Frameworks und Bibliotheken verwenden, die bereits die IOptions<TOptions>-Schnittstelle verwenden und nicht die von IOptionsMonitor<TOptions> bereitgestellten Szenarios benötigen.You may continue to use IOptions<TOptions> in existing frameworks and libraries that already use the IOptions<TOptions> interface and don't require the scenarios provided by IOptionsMonitor<TOptions>.

Allgemeine OptionskonfigurationGeneral options configuration

Die allgemeine Optionskonfiguration wird als Beispiel 1 in der Beispiel-App veranschaulicht.General options configuration is demonstrated as Example 1 in the sample app.

Eine Optionsklasse muss nicht abstrakt sein und über einen öffentlichen parameterlosen Konstruktor verfügen.An options class must be non-abstract with a public parameterless constructor. Die folgende Klasse MyOptions verfügt über die zwei Eigenschaften: Option1 und Option2.The following class, MyOptions, has two properties, Option1 and Option2. Das Festlegen von Standardwerten ist optional, aber der Klassenkonstruktor im folgenden Beispiel legt den Standardwert von Option1 fest.Setting default values is optional, but the class constructor in the following example sets the default value of Option1. Option2 hat den Standardwert festgelegt, indem die Eigenschaft direkt initialisiert wurde (Models/MyOptions.cs):Option2 has a default value set by initializing the property directly (Models/MyOptions.cs):

public class MyOptions
{
    public MyOptions()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

Die MyOptions-Klasse wird zum Dienstcontainer mit Configure hinzugefügt und an die Konfiguration gebunden:The MyOptions class is added to the service container with Configure and bound to configuration:

// Example #1: General configuration
// Register the Configuration instance which MyOptions binds against.
services.Configure<MyOptions>(Configuration);

Das folgende Seitenmodel verwendet konstruktorbasierte Dependency Injection mit IOptionsMonitor<TOptions>, um auf die Einstellungen zugreifen zu können (Pages/Index.cshtml.cs):The following page model uses constructor dependency injection with IOptionsMonitor<TOptions> to access the settings (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #1: Simple options
var option1 = _options.Option1;
var option2 = _options.Option2;
SimpleOptions = $"option1 = {option1}, option2 = {option2}";

Die appsettings.json-Datei des Beispiels gibt Werte für option1 und option2 an:The sample's appsettings.json file specifies values for option1 and option2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Wenn die Anwendung ausgeführt wird, gibt die OnGet-Methode des Seitenmodells eine Zeichenfolge zurück, die die Werte der Optionsklasse anzeigt:When the app is run, the page model's OnGet method returns a string showing the option class values:

option1 = value1_from_json, option2 = -1

Hinweis

Wenn Sie eine benutzerdefinierte ConfigurationBuilder-Klasse verwenden, um Konfigurationsoptionen aus einer Einstellungsdatei zu laden, bestätigen Sie, dass der Basispfad ordnungsgemäß festgelegt ist:When using a custom ConfigurationBuilder to load options configuration from a settings file, confirm that the base path is set correctly:

var configBuilder = new ConfigurationBuilder()
   .SetBasePath(Directory.GetCurrentDirectory())
   .AddJsonFile("appsettings.json", optional: true);
var config = configBuilder.Build();

services.Configure<MyOptions>(config);

Sie müssen den Basispfad nicht explizit festlegen, wenn Sie Konfigurationsoptionen über CreateDefaultBuilder aus der Einstellungsdatei laden.Explicitly setting the base path isn't required when loading options configuration from the settings file via CreateDefaultBuilder.

Konfigurieren von einfachen Optionen mit einem DelegatenConfigure simple options with a delegate

Das Konfigurieren von einfachen Optionen mit einem Delegaten wird als Beispiel 2 in der Beispiel-App veranschaulicht.Configuring simple options with a delegate is demonstrated as Example 2 in the sample app.

Verwenden Sie einen Delegaten zum Festlegen von Optionswerten.Use a delegate to set options values. Die Beispielanwendung verwendet die MyOptionsWithDelegateConfig-Klasse (Models/MyOptionsWithDelegateConfig.cs):The sample app uses the MyOptionsWithDelegateConfig class (Models/MyOptionsWithDelegateConfig.cs):

public class MyOptionsWithDelegateConfig
{
    public MyOptionsWithDelegateConfig()
    {
        // Set default value.
        Option1 = "value1_from_ctor";
    }
    
    public string Option1 { get; set; }
    public int Option2 { get; set; } = 5;
}

Im folgenden Code wird ein zweiter IConfigureOptions<TOptions>-Dienst zum Dienstcontainer hinzugefügt.In the following code, a second IConfigureOptions<TOptions> service is added to the service container. Er verwendet einen Delegaten zum Konfigurieren der Bindung mit MyOptionsWithDelegateConfig:It uses a delegate to configure the binding with MyOptionsWithDelegateConfig:

// Example #2: Options bound and configured by a delegate
services.Configure<MyOptionsWithDelegateConfig>(myOptions =>
{
    myOptions.Option1 = "value1_configured_by_delegate";
    myOptions.Option2 = 500;
});

Index.cshtml.cs:Index.cshtml.cs:

private readonly MyOptionsWithDelegateConfig _optionsWithDelegateConfig;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #2: Options configured by delegate
var delegate_config_option1 = _optionsWithDelegateConfig.Option1;
var delegate_config_option2 = _optionsWithDelegateConfig.Option2;
SimpleOptionsWithDelegateConfig = 
    $"delegate_option1 = {delegate_config_option1}, " +
    $"delegate_option2 = {delegate_config_option2}";

Sie können mehrere Konfigurationsanbieter hinzufügen.You can add multiple configuration providers. Konfigurationsanbieter sind über NuGet-Pakete verfügbar und werden in der Reihenfolge ihrer Registrierung angewendet.Configuration providers are available from NuGet packages and are applied in the order that they're registered. Weitere Informationen finden Sie unter Konfiguration in ASP.NET Core.For more information, see Konfiguration in ASP.NET Core.

Jeder Aufruf von Configure fügt einen IConfigureOptions<TOptions>-Dienst zum Dienstcontainer hinzu.Each call to Configure adds an IConfigureOptions<TOptions> service to the service container. Im vorherigen Beispiel wurden die Werte von Option1 und Option2 beide in appsettings.json angegeben, aber die Werte von Option1 und Option2 werden vom konfigurierten Delegaten überschrieben.In the preceding example, the values of Option1 and Option2 are both specified in appsettings.json, but the values of Option1 and Option2 are overridden by the configured delegate.

Wenn mehr als ein Konfigurationsdienst aktiviert ist, gewinnt die letzte angegebene Konfigurationsquelle und legt den Konfigurationswert fest.When more than one configuration service is enabled, the last configuration source specified wins and sets the configuration value. Wenn die Anwendung ausgeführt wird, gibt die OnGet-Methode des Seitenmodells eine Zeichenfolge zurück, die die Werte der Optionsklasse anzeigt:When the app is run, the page model's OnGet method returns a string showing the option class values:

delegate_option1 = value1_configured_by_delegate, delegate_option2 = 500

Konfigurieren von UnteroptionenSuboptions configuration

Das Konfigurieren von Unteroptionen wird als Beispiel 3 in der Beispiel-App veranschaulicht.Suboptions configuration is demonstrated as Example 3 in the sample app.

Anwendungen sollten Optionsklassen erstellen, die für bestimmte Szenariogruppen (Klassen) in der Anwendung gelten.Apps should create options classes that pertain to specific scenario groups (classes) in the app. Die Komponenten der Anwendung, die Konfigurationswerte erfordern, sollten nur über Zugriff auf die Konfigurationswerte verfügen, die sie verwenden.Parts of the app that require configuration values should only have access to the configuration values that they use.

Beim Binden von Optionen zur Konfiguration ist jede Eigenschaft im Optionstyp an einen Konfigurationsschlüssel des property[:sub-property:]-Formulars gebunden.When binding options to configuration, each property in the options type is bound to a configuration key of the form property[:sub-property:]. Die MyOptions.Option1-Eigenschaft ist beispielsweise an den Schlüssel Option1 gebunden, der von der option1-Eigenschaft in appsettings.json gelesen wird.For example, the MyOptions.Option1 property is bound to the key Option1, which is read from the option1 property in appsettings.json.

Im folgenden Code wird ein dritter IConfigureOptions<TOptions>-Dienst zum Dienstcontainer hinzugefügt.In the following code, a third IConfigureOptions<TOptions> service is added to the service container. Er verbindet MySubOptions mit dem subsection-Abschnitt der appSettings.json-Datei:It binds MySubOptions to the section subsection of the appsettings.json file:

// Example #3: Suboptions
// Bind options using a sub-section of the appsettings.json file.
services.Configure<MySubOptions>(Configuration.GetSection("subsection"));

Die GetSection-Methode erfordert den Namespace Microsoft.Extensions.Configuration.The GetSection method requires the Microsoft.Extensions.Configuration namespace.

Die appsettings.json-Datei des Beispiels definiert ein subsection-Element mit Schlüsseln für suboption1 und suboption2:The sample's appsettings.json file defines a subsection member with keys for suboption1 and suboption2:

{
  "option1": "value1_from_json",
  "option2": -1,
  "subsection": {
    "suboption1": "subvalue1_from_json",
    "suboption2": 200
  },
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*"
}

Die MySubOptions-Klasse definiert die Eigenschaften SubOption1 und SubOption2 zur Aufnahme der Optionswerte (Models/MySubOptions.cs):The MySubOptions class defines properties, SubOption1 and SubOption2, to hold the options values (Models/MySubOptions.cs):

public class MySubOptions
{
    public MySubOptions()
    {
        // Set default values.
        SubOption1 = "value1_from_ctor";
        SubOption2 = 5;
    }
    
    public string SubOption1 { get; set; }
    public int SubOption2 { get; set; }
}

Die OnGet-Methode des Seitenmodells gibt eine Zeichenfolge mit den Optionswerten (Pages/Index.cshtml.cs) zurück:The page model's OnGet method returns a string with the options values (Pages/Index.cshtml.cs):

private readonly MySubOptions _subOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #3: Suboptions
var subOption1 = _subOptions.SubOption1;
var subOption2 = _subOptions.SubOption2;
SubOptions = $"subOption1 = {subOption1}, subOption2 = {subOption2}";

Wenn die App ausgeführt wird, gibt die OnGet-Methode eine Zeichenfolge zurück, die die Werte der untergeordneten Optionsklasse anzeigt:When the app is run, the OnGet method returns a string showing the suboption class values:

subOption1 = subvalue1_from_json, subOption2 = 200

Optionen, die durch ein Ansichtsmodell oder mit direkter View Injection bereitgestellt werdenOptions provided by a view model or with direct view injection

Optionen, die durch ein Ansichtsmodell oder mit direkter View Injection bereitgestellt werden, werden im Beispiel 4 in der Beispiel-App veranschaulicht.Options provided by a view model or with direct view injection is demonstrated as Example 4 in the sample app.

Optionen können in einem Ansichtsmodell oder durch direkte Injection von IOptionsMonitor<TOptions> in eine Ansicht (Pages/Index.cshtml.cs) angegeben werden:Options can be supplied in a view model or by injecting IOptionsMonitor<TOptions> directly into a view (Pages/Index.cshtml.cs):

private readonly MyOptions _options;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #4: Bind options directly to the page
MyOptions = _options;

Die Beispiel-App zeigt das Einfügen von IOptionsMonitor<MyOptions> mit einer @inject-Anweisung:The sample app shows how to inject IOptionsMonitor<MyOptions> with an @inject directive:

@page
@model IndexModel
@using Microsoft.Extensions.Options
@inject IOptionsMonitor<MyOptions> OptionsAccessor
@{
    ViewData["Title"] = "Options Sample";
}

<h1>@ViewData["Title"]</h1>

Wenn die App ausgeführt wird, werden die Optionswerte in der gerenderten Seite angezeigt:When the app is run, the options values are shown in the rendered page:

Optionswerte Option1: value1_from_json und Option2: -1 werden aus dem Modell geladen und in die Ansicht eingefügt.

Neuladen der Konfigurationsdaten mit IOptionsSnapshotReload configuration data with IOptionsSnapshot

Das Neuladen der Konfigurationsdaten mit IOptionsSnapshot<TOptions> wird im Beispiel 5 in der Beispiel-App veranschaulicht.Reloading configuration data with IOptionsSnapshot<TOptions> is demonstrated in Example 5 in the sample app.

IOptionsSnapshot<TOptions> unterstützt das Neuladen von Optionen mit minimalem Verarbeitungsaufwand.IOptionsSnapshot<TOptions> supports reloading options with minimal processing overhead.

Optionen werden einmal pro Anforderung berechnet. Dies geschieht, wenn auf sie zugegriffen wird und sie für die Dauer der Anforderung zwischengespeichert werden.Options are computed once per request when accessed and cached for the lifetime of the request.

Im folgenden Beispiel wird veranschaulicht, wie eine neue IOptionsSnapshot<TOptions> nach den appsettings.json-Veränderungen erstellt wird (Pages/Index.cshtml.cs).The following example demonstrates how a new IOptionsSnapshot<TOptions> is created after appsettings.json changes (Pages/Index.cshtml.cs). Mehrere Anforderungen an den Server geben konstante Werte zurück, die von der appsettings.json-Datei bereitgestellt werden, bis die Datei geändert wird und die Konfiguration neu lädt.Multiple requests to the server return constant values provided by the appsettings.json file until the file is changed and configuration reloads.

private readonly MyOptions _snapshotOptions;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #5: Snapshot options
var snapshotOption1 = _snapshotOptions.Option1;
var snapshotOption2 = _snapshotOptions.Option2;
SnapshotOptions = 
    $"snapshot option1 = {snapshotOption1}, " +
    $"snapshot option2 = {snapshotOption2}";

Die folgende Abbildung zeigt die anfänglichen option1- und option2-Werte, die aus der appsettings.json-Datei geladen werden:The following image shows the initial option1 and option2 values loaded from the appsettings.json file:

snapshot option1 = value1_from_json, snapshot option2 = -1

Ändern Sie die Werte in der appsettings.json-Datei auf value1_from_json UPDATED und 200.Change the values in the appsettings.json file to value1_from_json UPDATED and 200. Speichern Sie die appsettings.json-Datei.Save the appsettings.json file. Aktualisieren Sie den Browser, um festzustellen, ob die Optionswerte aktualisiert wurden:Refresh the browser to see that the options values are updated:

snapshot option1 = value1_from_json UPDATED, snapshot option2 = 200

Unterstützung für benannte Optionen mit IConfigureNamedOptionsNamed options support with IConfigureNamedOptions

Unterstützung für benannte Optionen mit IConfigureNamedOptions<TOptions> wird als Beispiel 6 in der Beispiel-App veranschaulicht.Named options support with IConfigureNamedOptions<TOptions> is demonstrated as Example 6 in the sample app.

Die Unterstützung für benannte Optionen ermöglicht es der Anwendung, zwischen den Konfigurationen benannter Optionen zu unterscheiden.Named options support allows the app to distinguish between named options configurations. In der Beispiel-App werden benannte Optionen mit OptionsServiceCollectionExtensions.Configure deklariert. Dadurch wird wiederum die Erweiterungsmethode ConfigureNamedOptions<TOptions>.Configure aufgerufen.In the sample app, named options are declared with OptionsServiceCollectionExtensions.Configure, which calls the ConfigureNamedOptions<TOptions>.Configure extension method. Benannte Optionen Unterscheidung nach Groß-/Kleinschreibung.Named options are case sensitive.

// Example #6: Named options (named_options_1)
// Register the ConfigurationBuilder instance which MyOptions binds against.
// Specify that the options loaded from configuration are named
// "named_options_1".
services.Configure<MyOptions>("named_options_1", Configuration);

// Example #6: Named options (named_options_2)
// Specify that the options loaded from the MyOptions class are named
// "named_options_2".
// Use a delegate to configure option values.
services.Configure<MyOptions>("named_options_2", myOptions =>
{
    myOptions.Option1 = "named_options_2_value1_from_action";
});

Die Beispielanwendung greift mit Get auf die benannten Optionen zu (Pages/Index.cshtml.cs):The sample app accesses the named options with Get (Pages/Index.cshtml.cs):

private readonly MyOptions _named_options_1;
private readonly MyOptions _named_options_2;
public IndexModel(
    IOptionsMonitor<MyOptions> optionsAccessor, 
    IOptionsMonitor<MyOptionsWithDelegateConfig> optionsAccessorWithDelegateConfig, 
    IOptionsMonitor<MySubOptions> subOptionsAccessor, 
    IOptionsSnapshot<MyOptions> snapshotOptionsAccessor, 
    IOptionsSnapshot<MyOptions> namedOptionsAccessor)
{
    _options = optionsAccessor.CurrentValue;
    _optionsWithDelegateConfig = optionsAccessorWithDelegateConfig.CurrentValue;
    _subOptions = subOptionsAccessor.CurrentValue;
    _snapshotOptions = snapshotOptionsAccessor.Value;
    _named_options_1 = namedOptionsAccessor.Get("named_options_1");
    _named_options_2 = namedOptionsAccessor.Get("named_options_2");
}
// Example #6: Named options
var named_options_1 = 
    $"named_options_1: option1 = {_named_options_1.Option1}, " +
    $"option2 = {_named_options_1.Option2}";
var named_options_2 = 
    $"named_options_2: option1 = {_named_options_2.Option1}, " +
    $"option2 = {_named_options_2.Option2}";
NamedOptions = $"{named_options_1} {named_options_2}";

Bei der Ausführung der Beispielanwendung werden die benannten Optionen zurückgegeben:Running the sample app, the named options are returned:

named_options_1: option1 = value1_from_json, option2 = -1
named_options_2: option1 = named_options_2_value1_from_action, option2 = 5

named_options_1-Werte werden von der Konfiguration bereitgestellt. Sie werden aus der appsettings.json-Datei geladen.named_options_1 values are provided from configuration, which are loaded from the appsettings.json file. named_options_2-Werte werden bereitgestellt vom:named_options_2 values are provided by:

  • named_options_2-Delegat in ConfigureServices für Option1.The named_options_2 delegate in ConfigureServices for Option1.
  • Der Standardwert für Option2 wird von der MyOptions-Klasse bereitgestellt.The default value for Option2 provided by the MyOptions class.

Konfigurieren aller Optionen mit der ConfigureAll-MethodeConfigure all options with the ConfigureAll method

Konfigurieren Sie alle Optionsinstanzen mit der ConfigureAll-Methode.Configure all options instances with the ConfigureAll method. Der folgende Code konfiguriert Option1 für alle Konfigurationsinstanzen mit einem gemeinsamen Wert.The following code configures Option1 for all configuration instances with a common value. Fügen Sie der Startup.ConfigureServices-Methode manuell den folgenden Code hinzu:Add the following code manually to the Startup.ConfigureServices method:

services.ConfigureAll<MyOptions>(myOptions => 
{
    myOptions.Option1 = "ConfigureAll replacement value";
});

Das Ausführen der Beispielanwendung nach dem Hinzufügen des Codes führt zu folgendem Ergebnis:Running the sample app after adding the code produces the following result:

named_options_1: option1 = ConfigureAll replacement value, option2 = -1
named_options_2: option1 = ConfigureAll replacement value, option2 = 5

Hinweis

Alle Optionen sind benannte Instanzen.All options are named instances. Vorhandene IConfigureOptions<TOptions>-Instanzen werden behandelt, als ob sie auf die Options.DefaultName-Instanz abzielen. Diese ist string.Empty.Existing IConfigureOptions<TOptions> instances are treated as targeting the Options.DefaultName instance, which is string.Empty. IConfigureNamedOptions<TOptions> implementiert auch IConfigureOptions<TOptions>.IConfigureNamedOptions<TOptions> also implements IConfigureOptions<TOptions>. Die standardmäßige Implementierung von IOptionsFactory<TOptions> verfügt über eine Logik, um jede einzelne entsprechend zu verwenden.The default implementation of the IOptionsFactory<TOptions> has logic to use each appropriately. Die benannte Option null wird verwendet, um auf alle benannten Instanzen anstelle einer bestimmten benannten Instanz abzuzielen (ConfigureAll und PostConfigureAll verwenden diese Konvention).The null named option is used to target all of the named instances instead of a specific named instance (ConfigureAll and PostConfigureAll use this convention).

OptionsBuilder-APIOptionsBuilder API

OptionsBuilder<TOptions> dient zum Konfigurieren von TOptions-Instanzen.OptionsBuilder<TOptions> is used to configure TOptions instances. OptionsBuilder optimiert die Erstellung von benannten Optionen, da es sich nur um einen einzelnen Parameter für den ersten AddOptions<TOptions>(string optionsName)-Aufruf handelt statt um alle nachfolgenden Aufrufe.OptionsBuilder streamlines creating named options as it's only a single parameter to the initial AddOptions<TOptions>(string optionsName) call instead of appearing in all of the subsequent calls. Die Optionsvalidierung und die ConfigureOptions-Überladungen, die Dienstabhängigkeiten akzeptieren, sind nur über OptionsBuilder verfügbar.Options validation and the ConfigureOptions overloads that accept service dependencies are only available via OptionsBuilder.

// Options.DefaultName = "" is used.
services.AddOptions<MyOptions>().Configure(o => o.Property = "default");

services.AddOptions<MyOptions>("optionalName")
    .Configure(o => o.Property = "named");

Verwenden von DI-Diensten zum Konfigurieren von OptionenUse DI services to configure options

Beim Konfigurieren von Optionen haben Sie zwei Möglichkeiten, auf andere Dienste aus Dependency Injections zuzugreifen:You can access other services from dependency injection while configuring options in two ways:

Es empfiehlt sich das Übergeben eines Konfigurationsdelegaten an Konfigurieren, da das Erstellen eines Diensts etwas komplexer ist.We recommend passing a configuration delegate to Configure, since creating a service is more complex. Selbst einen eigenen Typ zu erstellen ist gleichbedeutend mit dem, was das Framework für Sie übernimmt, wenn Sie Konfigurieren verwenden.Creating your own type is equivalent to what the framework does for you when you use Configure. Wenn Konfigurieren aufgerufen wird, wird eine vorübergehende, generische IConfigureNamedOptions<TOptions> registriert, die über einen Konstruktor verfügt, der die angegeben generischen Diensttypen akzeptiert.Calling Configure registers a transient generic IConfigureNamedOptions<TOptions>, which has a constructor that accepts the generic service types specified.

Optionen für die PostkonfigurationOptions post-configuration

Legen Sie die Postkonfiguration mit IPostConfigureOptions<TOptions> fest.Set post-configuration with IPostConfigureOptions<TOptions>. Die Postkonfiguration erfolgt, nachdem die gesamte IConfigureOptions<TOptions>-Konfiguration abgeschlossen ist:Post-configuration runs after all IConfigureOptions<TOptions> configuration occurs:

services.PostConfigure<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

PostConfigure ist nach dem Konfigurieren der benannten Optionen verfügbar:PostConfigure is available to post-configure named options:

services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Verwenden Sie PostConfigureAll zur Postkonfiguration aller Konfigurationsinstanzen:Use PostConfigureAll to post-configure all configuration instances:

services.PostConfigureAll<MyOptions>(myOptions =>
{
    myOptions.Option1 = "post_configured_option1_value";
});

Zugreifen auf Optionen während des StartsAccessing options during startup

IOptions<TOptions> und IOptionsMonitor<TOptions> können in Startup.Configure verwendet werden, da Dienste erstellt werden, bevor die Configure-Methode ausgeführt wird.IOptions<TOptions> and IOptionsMonitor<TOptions> can be used in Startup.Configure, since services are built before the Configure method executes.

public void Configure(IApplicationBuilder app, IOptionsMonitor<MyOptions> optionsAccessor)
{
    var option1 = optionsAccessor.CurrentValue.Option1;
}

Verwenden Sie IOptions<TOptions> oder IOptionsMonitor<TOptions> nicht in Startup.ConfigureServices.Don't use IOptions<TOptions> or IOptionsMonitor<TOptions> in Startup.ConfigureServices. Es kann einen inkonsistenten Optionszustand geben. Dies liegt an der Reihenfolge der Dienstregistrierungen.An inconsistent options state may exist due to the ordering of service registrations.

Zusätzliche RessourcenAdditional resources