Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Varning
Den här versionen av ASP.NET Core stöds inte längre. Mer information finns i supportpolicyn för .NET och .NET Core. För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Viktigt!
Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps kommersiellt. Microsoft lämnar inga garantier, uttryckliga eller underförstådda, med avseende på den information som tillhandahålls här.
För den nuvarande utgåvan, se .NET 9-versionen av den här artikeln .
Av Rick Anderson.
Alternativmönstret använder klasser för att ge starkt skrivskyddad åtkomst till grupper med relaterade inställningar. När konfigurationsinställningarna isoleras efter scenario i separata klasser följer appen två viktiga principer för programvaruteknik:
-
Inkapsling:
- Klasser som är beroende av konfigurationsinställningar beror bara på de konfigurationsinställningar som de använder.
-
Separation av bekymmer:
- Inställningar för olika delar av appen är inte beroende av eller kopplade till varandra.
Alternativen tillhandahåller också en mekanism för att verifiera konfigurationsdata. Mer information finns i avsnittet Alternativvalidering .
Den här artikeln innehåller information om alternativmönstret i ASP.NET Core. Information om hur du använder alternativmönstret i konsolappar finns i Alternativmönster i .NET.
Bind hierarkisk konfiguration
Det bästa sättet att läsa relaterade konfigurationsvärden är att använda mönstret alternativ. Om du till exempel vill läsa följande konfigurationsvärden:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Skapa följande PositionOptions
klass:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
En options-klass:
- Måste vara icke-abstrakt.
- Har offentliga läs- och skrivegenskaper av den typ som har motsvarande objekt i konfigurationen är bundna.
- Har sina läs- och skrivegenskaper bundna till matchande poster i konfigurationen.
- Har inte sina fält bundna. I föregående kod är inte
Position
bunden. FältetPosition
används så att strängen"Position"
inte behöver hårdkodas i appen när klassen binds till en konfigurationsprovider.
Följande kod:
- Anropar ConfigurationBinder.Bind för att binda
PositionOptions
klassen till avsnittetPosition
. - Visar konfigurationsdata
Position
.
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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
ConfigurationBinder.Get<T>
binder och returnerar den angivna typen.
ConfigurationBinder.Get<T>
kan vara bekvämare än att använda ConfigurationBinder.Bind
. Följande kod visar hur du använder ConfigurationBinder.Get<T>
med PositionOptions
klassen:
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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
Bind tillåter också konkretion av en abstrakt klass. Överväg följande kod som använder den abstrakta klassen SomethingWithAName
:
namespace ConfigSample.Options;
public abstract class SomethingWithAName
{
public abstract string? Name { get; set; }
}
public class NameTitleOptions(int age) : SomethingWithAName
{
public const string NameTitle = "NameTitle";
public override string? Name { get; set; }
public string Title { get; set; } = string.Empty;
public int Age { get; set; } = age;
}
Följande kod visar konfigurationsvärdena NameTitleOptions
:
public class Test33Model : PageModel
{
private readonly IConfiguration Configuration;
public Test33Model(IConfiguration configuration)
{
Configuration = configuration;
}
public ContentResult OnGet()
{
var nameTitleOptions = new NameTitleOptions(22);
Configuration.GetSection(NameTitleOptions.NameTitle).Bind(nameTitleOptions);
return Content($"Title: {nameTitleOptions.Title} \n" +
$"Name: {nameTitleOptions.Name} \n" +
$"Age: {nameTitleOptions.Age}"
);
}
}
Anrop till Bind
är mindre strikta än anrop till Get<>
:
-
Bind
tillåter konkretion av ett abstrakt. -
Get<>
måste skapa en instans själv.
Mönstret för alternativ
En alternativ metod när du använder alternativmönstret är att binda Position
avsnittet och lägga till det i containern för beroendeinmatningstjänsten. I följande kod PositionOptions
läggs till i tjänstcontainern med Configure och är bunden till konfigurationen:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Med hjälp av föregående kod läser följande kod positionsalternativen:
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}");
}
}
I föregående kod läss inte ändringar i JSON-konfigurationsfilen när appen har startats. Om du vill läsa ändringar när appen har startats använder du IOptionsSnapshot.
Alternativgränssnitt
- Stöder inte :
- Läsning av konfigurationsdata när appen har startats.
- Namngivna alternativ
- Är registrerad som singleton och kan matas in i alla tjänstlivslängder.
- Är användbart i scenarier där alternativ ska beräknas om för varje begäran. Mer information finns i Använda IOptionsSnapshot för att läsa uppdaterade data.
- Är registrerad som Scoped och kan därför inte matas in i en Singleton-tjänst.
- Stöder namngivna alternativ
- Används för att hämta alternativ och hantera alternativmeddelanden för
TOptions
instanser. - Är registrerad som singleton och kan matas in i alla tjänstlivslängder.
- Stöder:
- Ändra meddelanden
- Namngivna alternativ
- Konfiguration som kan läsas in igen
- Ogiltiga selektiva alternativ (IOptionsMonitorCache<TOptions>)
Scenarier efter konfigurationen gör det möjligt att ställa in eller ändra alternativ när all IConfigureOptions<TOptions> konfiguration har inträffat.
IOptionsFactory<TOptions> ansvarar för att skapa nya alternativinstanser. Den har en enda Create metod. Standardimplementeringen tar alla registrerade IConfigureOptions<TOptions> och IPostConfigureOptions<TOptions> kör alla konfigurationer först, följt av efterkonfigurationen. Den skiljer mellan IConfigureNamedOptions<TOptions> och IConfigureOptions<TOptions> och anropar bara rätt gränssnitt.
IOptionsMonitorCache<TOptions> används av IOptionsMonitor<TOptions> för att cachelagrar TOptions
instanser. Ogiltigförklarar IOptionsMonitorCache<TOptions> alternativinstanser i övervakaren så att värdet omberäknas (TryRemove). Värden kan introduceras manuellt med TryAdd. Metoden Clear används när alla namngivna instanser ska återskapas på begäran.
Använda IOptionsSnapshot för att läsa uppdaterade data
Att använda IOptionsSnapshot<TOptions>:
- Alternativen beräknas en gång per begäran när de används och cachelagras under begärans livslängd.
- Kan medföra en betydande prestandaförsämring eftersom det är en Scoped-tjänst och beräknas om per begäran. Mer information finns i det här GitHub-problemet och Förbättra prestanda för konfigurationsbindning.
- Ändringar i konfigurationen läse när appen startar när du använder konfigurationsproviders som stöder läsning av uppdaterade konfigurationsvärden.
Skillnaden mellan IOptionsMonitor
och IOptionsSnapshot
är att:
-
IOptionsMonitor
är en Singleton-tjänst som hämtar aktuella alternativvärden när som helst, vilket är särskilt användbart i singleton-beroenden. -
IOptionsSnapshot
är en Scoped-tjänst och ger en ögonblicksbild av alternativen när objektetIOptionsSnapshot<T>
konstrueras. Ögonblicksbilder av alternativ är utformade för användning med tillfälliga och begränsade beroenden.
Följande kod använder 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}");
}
}
Följande kod registrerar en konfigurationsinstans som MyOptions
binder mot:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
I föregående kod läss ändringar i JSON-konfigurationsfilen när appen har startats.
IOptionsMonitor
Följande kod registrerar en konfigurationsinstans som MyOptions
binder mot.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
I följande exempel används 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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
Ange ett anpassat nyckelnamn för en konfigurationsegenskap med hjälp av ConfigurationKeyName
Som standard används egenskapsnamnen för options-klassen som nyckelnamn i konfigurationskällan. Om egenskapsnamnet är Title
är även nyckelnamnet i konfigurationen Title
.
När namnen skiljer sig åt kan du använda attributetConfigurationKeyName
för att ange nyckelnamnet i konfigurationskällan. Med den här tekniken kan du mappa en egenskap i konfigurationen till en i koden med ett annat namn.
Detta är användbart när egenskapsnamnet i konfigurationskällan inte är en giltig C#-identifierare eller när du vill använda ett annat namn i koden.
Tänk dig till exempel följande alternativklass:
public class PositionOptionsWithConfigurationKeyName
{
public const string Position = "Position";
[ConfigurationKeyName("position-title")]
public string Title { get; set; } = string.Empty;
[ConfigurationKeyName("position-name")]
public string Name { get; set; } = string.Empty;
}
Klassegenskaperna Title
och Name
är bundna till position-title
och position-name
från följande appsettings.json
fil:
{
"Position": {
"position-title": "Editor",
"position-name": "Joe Smith"
}
}
Namngivna alternativ stöder användning av IConfigureNamedOptions
Namngivna alternativ:
- Är användbara när flera konfigurationsavsnitt binder till samma egenskaper.
- Är skiftlägeskänsliga.
Överväg följande appsettings.json
fil:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
I stället för att skapa två klasser för bindning TopItem:Month
och TopItem:Year
används följande klass för varje avsnitt:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}
Följande kod konfigurerar de namngivna alternativen:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
var app = builder.Build();
Följande kod visar de namngivna alternativen:
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" );
}
}
Alla alternativ heter instanser.
IConfigureOptions<TOptions> instanser behandlas som mål för instansen Options.DefaultName
, som är string.Empty
.
IConfigureNamedOptions<TOptions> implementerar IConfigureOptions<TOptions>också . Standardimplementeringen av IOptionsFactory<TOptions> har logik för att använda var och en på rätt sätt. Det null
namngivna alternativet används för att rikta alla namngivna instanser i stället för en specifik namngiven instans.
ConfigureAll och PostConfigureAll använd den här konventionen.
OptionsBuilder API
OptionsBuilder<TOptions> används för att konfigurera TOptions
instanser.
OptionsBuilder
effektiviserar skapandet av namngivna alternativ eftersom det bara är en enda parameter till det första AddOptions<TOptions>(string optionsName)
anropet i stället för att visas i alla efterföljande anrop. Alternativvalidering och överlagringar ConfigureOptions
som accepterar tjänstberoenden är endast tillgängliga via OptionsBuilder
.
OptionsBuilder
används i avsnittet Alternativvalidering .
Se Använda AddOptions för att konfigurera anpassad databas för information om hur du lägger till en anpassad databas.
Använda DI-tjänster för att konfigurera alternativ
Tjänster kan nås från beroendeinmatning när alternativen konfigureras på två sätt:
Skicka ett konfigurationsombud till Configure på OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
Tillhandahåller överlagringar som Configure tillåter användning av upp till fem tjänster för att konfigurera alternativ:builder.Services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Skapa en typ som implementerar IConfigureOptions<TOptions> eller IConfigureNamedOptions<TOptions> registrerar typen som en tjänst.
Vi rekommenderar att du skickar ett konfigurationsombud till , eftersom det är mer komplext att Configureskapa en tjänst. Att skapa en typ motsvarar vad ramverket gör när det anropar Configure. Anrop Configure registrerar en tillfällig generisk IConfigureNamedOptions<TOptions>, som har en konstruktor som accepterar de angivna allmänna tjänsttyperna.
Alternativvalidering
Alternativvalidering gör att alternativvärden kan verifieras.
Överväg följande appsettings.json
fil:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Följande klass används för att binda till "MyConfig"
konfigurationsavsnittet och tillämpar ett par DataAnnotations
regler:
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; }
}
Följande kod:
- Anrop AddOptions för att få en OptionsBuilder<TOptions> som binder till
MyConfigOptions
klassen. - Anrop ValidateDataAnnotations för att aktivera validering med .
DataAnnotations
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
var app = builder.Build();
Tilläggsmetoden ValidateDataAnnotations
definieras i NuGet-paketet Microsoft.Extensions.Options.DataAnnotations . För webbappar som använder Microsoft.NET.Sdk.Web
SDK refereras det här paketet implicit från det delade ramverket.
Följande kod visar konfigurationsvärdena eller valideringsfelen:
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);
}
Följande kod tillämpar en mer komplex verifieringsregel med hjälp av ett ombud:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.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.
var app = builder.Build();
IValidateOptions<TOptions>
och IValidatableObject
Följande klass implementerar 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
Gör det möjligt att flytta valideringskoden från Program.cs
och till en klass.
Med hjälp av föregående kod aktiveras validering med Program.cs
följande kod:
using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
MyConfigOptions.MyConfig));
builder.Services.AddSingleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>();
var app = builder.Build();
Validering av alternativ stöder IValidatableObjectockså . Så här utför du validering på klassnivå av en klass i själva klassen:
- Implementera
IValidatableObject
gränssnittet och dess Validate metod i klassen. - Ring ValidateDataAnnotations in
Program.cs
.
ValidateOnStart
Alternativvalidering körs första gången en TOption
instans skapas. Det innebär till exempel när den första åtkomsten sker IOptionsSnapshot<TOptions>.Value
i en begärandepipeline eller när IOptionsMonitor<TOptions>.Get(string)
den anropas på inställningar som finns. När inställningarna har lästs in igen körs verifieringen igen. Den ASP.NET Core-körningen används OptionsCache<TOptions> för att cachelagra alternativinstansen när den har skapats.
Om du vill köra alternativvalidering ivrigt när appen startar anropar du ValidateOnStart<TOptions>(OptionsBuilder<TOptions>):Program.cs
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Alternativ efter konfiguration
Ange efterkonfiguration med IPostConfigureOptions<TOptions>. Efterkonfigurationen körs efter att all IConfigureOptions<TOptions> konfiguration har utförts:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
PostConfigure är tillgängligt för efterkonfigurering av namngivna alternativ:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
myOptions.Name = "post_configured_name_value";
myOptions.Model = "post_configured_model_value";
});
var app = builder.Build();
Använd PostConfigureAll för att efterkonfigurera alla konfigurationsinstanser:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
Åtkomstalternativ i Program.cs
För att komma åt IOptions<TOptions> eller IOptionsMonitor<TOptions> i Program.cs
, ring GetRequiredService på WebApplication.Services:
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Ytterligare resurser
Av Kirk Larkin och Rick Anderson.
Alternativmönstret använder klasser för att ge starkt skrivskyddad åtkomst till grupper med relaterade inställningar. När konfigurationsinställningarna isoleras efter scenario i separata klasser följer appen två viktiga principer för programvaruteknik:
-
Inkapsling:
- Klasser som är beroende av konfigurationsinställningar beror bara på de konfigurationsinställningar som de använder.
-
Separation av bekymmer:
- Inställningar för olika delar av appen är inte beroende av eller kopplade till varandra.
Alternativen tillhandahåller också en mekanism för att verifiera konfigurationsdata. Mer information finns i avsnittet Alternativvalidering .
Den här artikeln innehåller information om alternativmönstret i ASP.NET Core. Information om hur du använder alternativmönstret i konsolappar finns i Alternativmönster i .NET.
Bind hierarkisk konfiguration
Det bästa sättet att läsa relaterade konfigurationsvärden är att använda mönstret alternativ. Om du till exempel vill läsa följande konfigurationsvärden:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Skapa följande PositionOptions
klass:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
En options-klass:
- Måste vara icke-abstrakt med en offentlig parameterlös konstruktor.
- Alla offentliga läs- och skrivegenskaper av typen är bundna.
- Fält är inte bundna. I föregående kod är inte
Position
bunden. FältetPosition
används så att strängen"Position"
inte behöver hårdkodas i appen när klassen binds till en konfigurationsprovider.
Följande kod:
- Anropar ConfigurationBinder.Bind för att binda
PositionOptions
klassen till avsnittetPosition
. - Visar konfigurationsdata
Position
.
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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
ConfigurationBinder.Get<T>
binder och returnerar den angivna typen.
ConfigurationBinder.Get<T>
kan vara bekvämare än att använda ConfigurationBinder.Bind
. Följande kod visar hur du använder ConfigurationBinder.Get<T>
med PositionOptions
klassen:
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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
En alternativ metod när du använder alternativmönstret är att binda Position
avsnittet och lägga till det i containern för beroendeinmatningstjänsten. I följande kod PositionOptions
läggs till i tjänstcontainern med Configure och är bunden till konfigurationen:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Med hjälp av föregående kod läser följande kod positionsalternativen:
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}");
}
}
I föregående kod läss inte ändringar i JSON-konfigurationsfilen när appen har startats. Om du vill läsa ändringar när appen har startats använder du IOptionsSnapshot.
Alternativgränssnitt
- Stöder inte :
- Läsning av konfigurationsdata när appen har startats.
- Namngivna alternativ
- Är registrerad som singleton och kan matas in i alla tjänstlivslängder.
- Är användbart i scenarier där alternativ ska beräknas om för varje begäran. Mer information finns i Använda IOptionsSnapshot för att läsa uppdaterade data.
- Är registrerad som Scoped och kan därför inte matas in i en Singleton-tjänst.
- Stöder namngivna alternativ
- Används för att hämta alternativ och hantera alternativmeddelanden för
TOptions
instanser. - Är registrerad som singleton och kan matas in i alla tjänstlivslängder.
- Stöder:
- Ändra meddelanden
- Namngivna alternativ
- Konfiguration som kan läsas in igen
- Ogiltiga selektiva alternativ (IOptionsMonitorCache<TOptions>)
Scenarier efter konfigurationen gör det möjligt att ställa in eller ändra alternativ när all IConfigureOptions<TOptions> konfiguration har inträffat.
IOptionsFactory<TOptions> ansvarar för att skapa nya alternativinstanser. Den har en enda Create metod. Standardimplementeringen tar alla registrerade IConfigureOptions<TOptions> och IPostConfigureOptions<TOptions> kör alla konfigurationer först, följt av efterkonfigurationen. Den skiljer mellan IConfigureNamedOptions<TOptions> och IConfigureOptions<TOptions> och anropar bara rätt gränssnitt.
IOptionsMonitorCache<TOptions> används av IOptionsMonitor<TOptions> för att cachelagrar TOptions
instanser. Ogiltigförklarar IOptionsMonitorCache<TOptions> alternativinstanser i övervakaren så att värdet omberäknas (TryRemove). Värden kan introduceras manuellt med TryAdd. Metoden Clear används när alla namngivna instanser ska återskapas på begäran.
Använda IOptionsSnapshot för att läsa uppdaterade data
Att använda IOptionsSnapshot<TOptions>:
- Alternativen beräknas en gång per begäran när de används och cachelagras under begärans livslängd.
- Kan medföra en betydande prestandaförsämring eftersom det är en Scoped-tjänst och beräknas om per begäran. Mer information finns i det här GitHub-problemet och Förbättra prestanda för konfigurationsbindning.
- Ändringar i konfigurationen läse när appen startar när du använder konfigurationsproviders som stöder läsning av uppdaterade konfigurationsvärden.
Skillnaden mellan IOptionsMonitor
och IOptionsSnapshot
är att:
-
IOptionsMonitor
är en Singleton-tjänst som hämtar aktuella alternativvärden när som helst, vilket är särskilt användbart i singleton-beroenden. -
IOptionsSnapshot
är en Scoped-tjänst och ger en ögonblicksbild av alternativen när objektetIOptionsSnapshot<T>
konstrueras. Ögonblicksbilder av alternativ är utformade för användning med tillfälliga och begränsade beroenden.
Följande kod använder 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}");
}
}
Följande kod registrerar en konfigurationsinstans som MyOptions
binder mot:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
I föregående kod läss ändringar i JSON-konfigurationsfilen när appen har startats.
IOptionsMonitor
Följande kod registrerar en konfigurationsinstans som MyOptions
binder mot.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
I följande exempel används 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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
Namngivna alternativ stöder användning av IConfigureNamedOptions
Namngivna alternativ:
- Är användbara när flera konfigurationsavsnitt binder till samma egenskaper.
- Är skiftlägeskänsliga.
Överväg följande appsettings.json
fil:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
I stället för att skapa två klasser för bindning TopItem:Month
och TopItem:Year
används följande klass för varje avsnitt:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; } = string.Empty;
public string Model { get; set; } = string.Empty;
}
Följande kod konfigurerar de namngivna alternativen:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
var app = builder.Build();
Följande kod visar de namngivna alternativen:
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" );
}
}
Alla alternativ heter instanser.
IConfigureOptions<TOptions> instanser behandlas som mål för instansen Options.DefaultName
, som är string.Empty
.
IConfigureNamedOptions<TOptions> implementerar IConfigureOptions<TOptions>också . Standardimplementeringen av IOptionsFactory<TOptions> har logik för att använda var och en på rätt sätt. Det null
namngivna alternativet används för att rikta alla namngivna instanser i stället för en specifik namngiven instans.
ConfigureAll och PostConfigureAll använd den här konventionen.
OptionsBuilder API
OptionsBuilder<TOptions> används för att konfigurera TOptions
instanser.
OptionsBuilder
effektiviserar skapandet av namngivna alternativ eftersom det bara är en enda parameter till det första AddOptions<TOptions>(string optionsName)
anropet i stället för att visas i alla efterföljande anrop. Alternativvalidering och överlagringar ConfigureOptions
som accepterar tjänstberoenden är endast tillgängliga via OptionsBuilder
.
OptionsBuilder
används i avsnittet Alternativvalidering .
Se Använda AddOptions för att konfigurera anpassad databas för information om hur du lägger till en anpassad databas.
Använda DI-tjänster för att konfigurera alternativ
Tjänster kan nås från beroendeinmatning när alternativen konfigureras på två sätt:
Skicka ett konfigurationsombud till Configure på OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
Tillhandahåller överlagringar som Configure tillåter användning av upp till fem tjänster för att konfigurera alternativ:builder.Services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Skapa en typ som implementerar IConfigureOptions<TOptions> eller IConfigureNamedOptions<TOptions> registrerar typen som en tjänst.
Vi rekommenderar att du skickar ett konfigurationsombud till , eftersom det är mer komplext att Configureskapa en tjänst. Att skapa en typ motsvarar vad ramverket gör när det anropar Configure. Anrop Configure registrerar en tillfällig generisk IConfigureNamedOptions<TOptions>, som har en konstruktor som accepterar de angivna allmänna tjänsttyperna.
Alternativvalidering
Alternativvalidering gör att alternativvärden kan verifieras.
Överväg följande appsettings.json
fil:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Följande klass används för att binda till "MyConfig"
konfigurationsavsnittet och tillämpar ett par DataAnnotations
regler:
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; }
}
Följande kod:
- Anrop AddOptions för att få en OptionsBuilder<TOptions> som binder till
MyConfigOptions
klassen. - Anrop ValidateDataAnnotations för att aktivera validering med .
DataAnnotations
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations();
var app = builder.Build();
Tilläggsmetoden ValidateDataAnnotations
definieras i NuGet-paketet Microsoft.Extensions.Options.DataAnnotations . För webbappar som använder Microsoft.NET.Sdk.Web
SDK refereras det här paketet implicit från det delade ramverket.
Följande kod visar konfigurationsvärdena eller valideringsfelen:
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);
}
Följande kod tillämpar en mer komplex verifieringsregel med hjälp av ett ombud:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.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.
var app = builder.Build();
IValidateOptions<TOptions>
och IValidatableObject
Följande klass implementerar 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
Gör det möjligt att flytta valideringskoden från Program.cs
och till en klass.
Med hjälp av föregående kod aktiveras validering med Program.cs
följande kod:
using Microsoft.Extensions.Options;
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.Configure<MyConfigOptions>(builder.Configuration.GetSection(
MyConfigOptions.MyConfig));
builder.Services.AddSingleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>();
var app = builder.Build();
Validering av alternativ stöder IValidatableObjectockså . Så här utför du validering på klassnivå av en klass i själva klassen:
- Implementera
IValidatableObject
gränssnittet och dess Validate metod i klassen. - Ring ValidateDataAnnotations in
Program.cs
.
ValidateOnStart
Alternativvalidering körs första gången en IOptions<TOptions>, IOptionsSnapshot<TOptions>eller IOptionsMonitor<TOptions> implementering skapas. Om du vill köra alternativvalidering ivrigt när appen startar anropar du ValidateOnStart :Program.cs
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Alternativ efter konfiguration
Ange efterkonfiguration med IPostConfigureOptions<TOptions>. Efterkonfigurationen körs efter att all IConfigureOptions<TOptions> konfiguration har utförts:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigure<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
PostConfigure är tillgängligt för efterkonfigurering av namngivna alternativ:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<TopItemSettings>(TopItemSettings.Month,
builder.Configuration.GetSection("TopItem:Month"));
builder.Services.Configure<TopItemSettings>(TopItemSettings.Year,
builder.Configuration.GetSection("TopItem:Year"));
builder.Services.PostConfigure<TopItemSettings>("Month", myOptions =>
{
myOptions.Name = "post_configured_name_value";
myOptions.Model = "post_configured_model_value";
});
var app = builder.Build();
Använd PostConfigureAll för att efterkonfigurera alla konfigurationsinstanser:
using OptionsValidationSample.Configuration;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig));
builder.Services.PostConfigureAll<MyConfigOptions>(myOptions =>
{
myOptions.Key1 = "post_configured_key1_value";
});
Åtkomstalternativ i Program.cs
För att komma åt IOptions<TOptions> eller IOptionsMonitor<TOptions> i Program.cs
, ring GetRequiredService på WebApplication.Services:
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Ytterligare resurser
Av Kirk Larkin och Rick Anderson.
Alternativmönstret använder klasser för att ge starkt skrivskyddad åtkomst till grupper med relaterade inställningar. När konfigurationsinställningarna isoleras efter scenario i separata klasser följer appen två viktiga principer för programvaruteknik:
-
Inkapsling:
- Klasser som är beroende av konfigurationsinställningar beror bara på de konfigurationsinställningar som de använder.
-
Separation av bekymmer:
- Inställningar för olika delar av appen är inte beroende av eller kopplade till varandra.
Alternativen tillhandahåller också en mekanism för att verifiera konfigurationsdata. Mer information finns i avsnittet Alternativvalidering .
Det här avsnittet innehåller information om alternativmönstret i ASP.NET Core. Information om hur du använder alternativmönstret i konsolappar finns i Alternativmönster i .NET.
Visa eller ladda ned exempelkod (hur du laddar ned)
Bind hierarkisk konfiguration
Det bästa sättet att läsa relaterade konfigurationsvärden är att använda mönstret alternativ. Om du till exempel vill läsa följande konfigurationsvärden:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Skapa följande PositionOptions
klass:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; }
public string Name { get; set; }
}
En options-klass:
- Måste vara icke-abstrakt med en offentlig parameterlös konstruktor.
- Alla offentliga läs- och skrivegenskaper av typen är bundna.
- Fält är inte bundna. I föregående kod är inte
Position
bunden. EgenskapenPosition
används så att strängen"Position"
inte behöver hårdkodas i appen när klassen binds till en konfigurationsprovider.
Följande kod:
- Anropar ConfigurationBinder.Bind för att binda
PositionOptions
klassen till avsnittetPosition
. - Visar konfigurationsdata
Position
.
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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
ConfigurationBinder.Get<T>
binder och returnerar den angivna typen.
ConfigurationBinder.Get<T>
kan vara bekvämare än att använda ConfigurationBinder.Bind
. Följande kod visar hur du använder ConfigurationBinder.Get<T>
med PositionOptions
klassen:
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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
En alternativ metod när du använder alternativmönstret är att binda Position
avsnittet och lägga till det i containern för beroendeinmatningstjänsten. I följande kod PositionOptions
läggs till i tjänstcontainern med Configure och är bunden till konfigurationen:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(
PositionOptions.Position));
services.AddRazorPages();
}
Med hjälp av föregående kod läser följande kod positionsalternativen:
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}");
}
}
I föregående kod läss inte ändringar i JSON-konfigurationsfilen när appen har startats. Om du vill läsa ändringar när appen har startats använder du IOptionsSnapshot.
Alternativgränssnitt
- Stöder inte :
- Läsning av konfigurationsdata när appen har startats.
- Namngivna alternativ
- Är registrerad som singleton och kan matas in i alla tjänstlivslängder.
- Är användbart i scenarier där alternativ ska beräknas om för varje begäran. Mer information finns i Använda IOptionsSnapshot för att läsa uppdaterade data.
- Är registrerad som Omfång och kan därför inte matas in i en Singleton-tjänst.
- Stöder namngivna alternativ
- Används för att hämta alternativ och hantera alternativmeddelanden för
TOptions
instanser. - Är registrerad som singleton och kan matas in i alla tjänstlivslängder.
- Stöder:
- Ändra meddelanden
- Namngivna alternativ
- Konfiguration som kan läsas in igen
- Ogiltiga selektiva alternativ (IOptionsMonitorCache<TOptions>)
Scenarier efter konfigurationen gör det möjligt att ställa in eller ändra alternativ när all IConfigureOptions<TOptions> konfiguration har inträffat.
IOptionsFactory<TOptions> ansvarar för att skapa nya alternativinstanser. Den har en enda Create metod. Standardimplementeringen tar alla registrerade IConfigureOptions<TOptions> och IPostConfigureOptions<TOptions> kör alla konfigurationer först, följt av efterkonfigurationen. Den skiljer mellan IConfigureNamedOptions<TOptions> och IConfigureOptions<TOptions> och anropar bara rätt gränssnitt.
IOptionsMonitorCache<TOptions> används av IOptionsMonitor<TOptions> för att cachelagrar TOptions
instanser. Ogiltigförklarar IOptionsMonitorCache<TOptions> alternativinstanser i övervakaren så att värdet omberäknas (TryRemove). Värden kan introduceras manuellt med TryAdd. Metoden Clear används när alla namngivna instanser ska återskapas på begäran.
Använda IOptionsSnapshot för att läsa uppdaterade data
Med hjälp IOptionsSnapshot<TOptions>av beräknas alternativen en gång per begäran när de används och cachelagras under begärans livslängd. Ändringar i konfigurationen läse när appen startar när du använder konfigurationsproviders som stöder läsning av uppdaterade konfigurationsvärden.
Skillnaden mellan IOptionsMonitor
och IOptionsSnapshot
är att:
-
IOptionsMonitor
är en Singleton-tjänst som hämtar aktuella alternativvärden när som helst, vilket är särskilt användbart i singleton-beroenden. -
IOptionsSnapshot
är en Scoped-tjänst och ger en ögonblicksbild av alternativen när objektetIOptionsSnapshot<T>
konstrueras. Ögonblicksbilder av alternativ är utformade för användning med tillfälliga och begränsade beroenden.
Följande kod använder 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}");
}
}
Följande kod registrerar en konfigurationsinstans som MyOptions
binder mot:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
I föregående kod läss ändringar i JSON-konfigurationsfilen när appen har startats.
IOptionsMonitor
Följande kod registrerar en konfigurationsinstans som MyOptions
binder mot.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
I följande exempel används 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}");
}
}
I föregående kod läses som standard ändringar i JSON-konfigurationsfilen när appen har startats.
Namngivna alternativ stöder användning av IConfigureNamedOptions
Namngivna alternativ:
- Är användbara när flera konfigurationsavsnitt binder till samma egenskaper.
- Är skiftlägeskänsliga.
Överväg följande appsettings.json
fil:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
I stället för att skapa två klasser för bindning TopItem:Month
och TopItem:Year
används följande klass för varje avsnitt:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; }
public string Model { get; set; }
}
Följande kod konfigurerar de namngivna alternativen:
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();
}
Följande kod visar de namngivna alternativen:
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" );
}
}
Alla alternativ heter instanser.
IConfigureOptions<TOptions> instanser behandlas som mål för instansen Options.DefaultName
, som är string.Empty
.
IConfigureNamedOptions<TOptions> implementerar IConfigureOptions<TOptions>också . Standardimplementeringen av IOptionsFactory<TOptions> har logik för att använda var och en på rätt sätt. Det null
namngivna alternativet används för att rikta alla namngivna instanser i stället för en specifik namngiven instans.
ConfigureAll och PostConfigureAll använd den här konventionen.
OptionsBuilder API
OptionsBuilder<TOptions> används för att konfigurera TOptions
instanser.
OptionsBuilder
effektiviserar skapandet av namngivna alternativ eftersom det bara är en enda parameter till det första AddOptions<TOptions>(string optionsName)
anropet i stället för att visas i alla efterföljande anrop. Alternativvalidering och överlagringar ConfigureOptions
som accepterar tjänstberoenden är endast tillgängliga via OptionsBuilder
.
OptionsBuilder
används i avsnittet Alternativvalidering .
Se Använda AddOptions för att konfigurera anpassad databas för information om hur du lägger till en anpassad databas.
Använda DI-tjänster för att konfigurera alternativ
Tjänster kan nås från beroendeinmatning när alternativen konfigureras på två sätt:
Skicka ett konfigurationsombud till Configure på OptionsBuilder<TOptions>.
OptionsBuilder<TOptions>
Tillhandahåller överlagringar som Configure tillåter användning av upp till fem tjänster för att konfigurera alternativ:services.AddOptions<MyOptions>("optionalName") .Configure<Service1, Service2, Service3, Service4, Service5>( (o, s, s2, s3, s4, s5) => o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Skapa en typ som implementerar IConfigureOptions<TOptions> eller IConfigureNamedOptions<TOptions> registrerar typen som en tjänst.
Vi rekommenderar att du skickar ett konfigurationsombud till , eftersom det är mer komplext att Configureskapa en tjänst. Att skapa en typ motsvarar vad ramverket gör när det anropar Configure. Anrop Configure registrerar en tillfällig generisk IConfigureNamedOptions<TOptions>, som har en konstruktor som accepterar de angivna allmänna tjänsttyperna.
Alternativvalidering
Alternativvalidering gör att alternativvärden kan verifieras.
Överväg följande appsettings.json
fil:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Följande klass binder till konfigurationsavsnittet "MyConfig"
och tillämpar ett par DataAnnotations
regler:
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; }
}
Följande kod:
- Anrop AddOptions för att få en OptionsBuilder<TOptions> som binder till
MyConfigOptions
klassen. - Anrop ValidateDataAnnotations för att aktivera validering med .
DataAnnotations
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();
}
Tilläggsmetoden ValidateDataAnnotations
definieras i NuGet-paketet Microsoft.Extensions.Options.DataAnnotations . För webbappar som använder Microsoft.NET.Sdk.Web
SDK refereras det här paketet implicit från det delade ramverket.
Följande kod visar konfigurationsvärdena eller valideringsfelen:
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);
}
Följande kod tillämpar en mer komplex verifieringsregel med hjälp av ett ombud:
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 komplex validering
Följande klass implementerar 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
Gör det möjligt att flytta valideringskoden från StartUp
och till en klass.
Med hjälp av föregående kod aktiveras validering med Startup.ConfigureServices
följande kod:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfigOptions>(Configuration.GetSection(
MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>());
services.AddControllersWithViews();
}
Alternativ efter konfiguration
Ange efterkonfiguration med IPostConfigureOptions<TOptions>. Efterkonfigurationen körs efter att all IConfigureOptions<TOptions> konfiguration har utförts:
services.PostConfigure<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
PostConfigure är tillgängligt för efterkonfigurering av namngivna alternativ:
services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
Använd PostConfigureAll för att efterkonfigurera alla konfigurationsinstanser:
services.PostConfigureAll<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
Komma åt alternativ under start
IOptions<TOptions> och IOptionsMonitor<TOptions> kan användas i Startup.Configure
, eftersom tjänster skapas innan Configure
metoden körs.
public void Configure(IApplicationBuilder app,
IOptionsMonitor<MyOptions> optionsAccessor)
{
var option1 = optionsAccessor.CurrentValue.Option1;
}
Använd IOptions<TOptions> inte eller IOptionsMonitor<TOptions> i Startup.ConfigureServices
. Det kan finnas ett inkonsekvent alternativtillstånd på grund av ordningen på tjänstregistreringar.
NuGet-paketet Options.ConfigurationExtensions
Paketet Microsoft.Extensions.Options.ConfigurationExtensions refereras implicit till i ASP.NET Core-appar.
ASP.NET Core