Zdarzenia
Power BI DataViz World Championships
14 lut, 16 - 31 mar, 16
Z 4 szans na wejście, można wygrać pakiet konferencji i zrobić go do LIVE Grand Finale w Las Vegas
Dowiedz się więcejTa przeglądarka nie jest już obsługiwana.
Przejdź na przeglądarkę Microsoft Edge, aby korzystać z najnowszych funkcji, aktualizacji zabezpieczeń i pomocy technicznej.
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autor: Rick Anderson.
Wzorzec opcji używa klas w celu zapewnienia silnie typizowanego dostępu do grup powiązanych ustawień. Gdy ustawienia konfiguracji są izolowane według scenariusza w oddzielnych klasach, aplikacja jest zgodna z dwoma ważnymi zasadami inżynierii oprogramowania:
Opcje udostępniają również mechanizm sprawdzania poprawności danych konfiguracji. Aby uzyskać więcej informacji, zobacz sekcję Walidacja opcji.
Ten artykuł zawiera informacje na temat wzorca opcji w programie ASP.NET Core. Aby uzyskać informacje na temat używania wzorca opcji w aplikacjach konsoli, zobacz Wzorzec opcji na platformie .NET.
Preferowanym sposobem odczytywania powiązanych wartości konfiguracji jest użycie wzorca opcji. Aby na przykład odczytać następujące wartości konfiguracji:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Utwórz następującą klasę PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
Klasa opcji:
Position
nie jest powiązany. Dzięki użyciu pola Position
ciąg "Position"
nie musi być ustalony w aplikacji w przypadku tworzenia powiązania klasy z dostawcą konfiguracji.Następujący kod powoduje:
PositionOptions
z sekcją Position
.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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Element ConfigurationBinder.Get<T>
tworzy powiązanie i zwraca określony typ. Element ConfigurationBinder.Get<T>
może być wygodniejszy w użyciu niż element ConfigurationBinder.Bind
. W poniższym kodzie pokazano sposób użycia elementu ConfigurationBinder.Get<T>
z klasą PositionOptions
:
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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Powiązanie umożliwia również konkrecję klasy abstrakcyjnej. Rozważ następujący kod, który używa klasy SomethingWithAName
abstrakcyjnej :
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;
}
Poniższy kod wyświetla NameTitleOptions
wartości konfiguracji:
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}"
);
}
}
Wywołania do elementu Bind
są mniej rygorystyczne niż wywołania do elementu Get<>
:
Bind
umożliwia konkrecję abstrakcyjnego.Get<>
musi utworzyć samo wystąpienie.Alternatywne podejście w przypadku korzystania z wzorca opcji to utworzenie powiązania sekcji Position
i dodanie go do kontenera usługi wstrzykiwania zależności. W poniższym kodzie element PositionOptions
jest dodawany do kontenera usługi przy użyciu Configure, a następnie jest tworzone jego powiązanie z konfiguracją:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Przy użyciu poprzedniego kodu następujący kod odczytuje opcje położenia:
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}");
}
}
W poprzednim kodzie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji nie są odczytywane. Aby odczytać zmiany po uruchomieniu aplikacji, użyj elementu IOptionsSnapshot.
TOptions
wystąpień.Scenariusze po konfiguracji umożliwiają ustawienie lub zmianę opcji po zakończeniu wszystkich IConfigureOptions<TOptions> konfiguracji.
IOptionsFactory<TOptions> jest odpowiedzialny za tworzenie nowych wystąpień opcji. Ma jedną Create metodę. Domyślna implementacja pobiera wszystkie zarejestrowane IConfigureOptions<TOptions> i IPostConfigureOptions<TOptions> uruchamia najpierw wszystkie konfiguracje, a następnie po konfiguracji. Rozróżnia między elementami IConfigureNamedOptions<TOptions> i IConfigureOptions<TOptions> i wywołuje tylko odpowiedni interfejs.
IOptionsMonitorCache<TOptions> jest używany przez IOptionsMonitor<TOptions> program do buforowania TOptions
wystąpień. Unieważnia IOptionsMonitorCache<TOptions> wystąpienia opcji w monitorze, aby wartość została ponownie skompilowana (TryRemove). Wartości można wprowadzić ręcznie za pomocą TryAddpolecenia . Metoda Clear jest używana, gdy wszystkie nazwane wystąpienia powinny być ponownie tworzone na żądanie.
Za pomocą polecenia IOptionsSnapshot<TOptions>:
Różnica między elementami IOptionsMonitor
i IOptionsSnapshot
polega na tym, że:
IOptionsMonitor
jest usługą Singleton, która w dowolnym momencie pobiera bieżące wartości opcji, co jest szczególnie przydatne w zależnościach pojedynczych.IOptionsSnapshot
jest usługą o określonym zakresie i udostępnia migawkę opcji w momencie IOptionsSnapshot<T>
konstruowania obiektu. Migawki opcji są przeznaczone do użytku z zależnościami przejściowymi i o określonym zakresie.Poniższy kod używa metody 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}");
}
}
Poniższy kod rejestruje wystąpienie konfiguracji, które MyOptions
wiąże się z:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
W poprzednim kodzie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Poniższy kod rejestruje wystąpienie konfiguracji, które MyOptions
jest powiązane z.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
W poniższym przykładzie użyto metody 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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Nazwane opcje:
Rozważ użycie następującego pliku appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Zamiast tworzyć dwie klasy do powiązania TopItem:Month
i TopItem:Year
, dla każdej sekcji jest używana następująca klasa:
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;
}
Poniższy kod konfiguruje nazwane opcje:
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();
Poniższy kod wyświetla nazwane opcje:
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" );
}
}
Wszystkie opcje są nazwane wystąpienia. IConfigureOptions<TOptions> wystąpienia są traktowane jako docelowe Options.DefaultName
wystąpienie, czyli string.Empty
. IConfigureNamedOptions<TOptions> implementuje IConfigureOptions<TOptions>również funkcję . Domyślna implementacja elementu IOptionsFactory<TOptions> ma logikę do użycia odpowiednio. Nazwana null
opcja służy do określania wartości docelowej wszystkich nazwanych wystąpień zamiast określonego nazwanego wystąpienia. ConfigureAll i PostConfigureAll stosować tę konwencję.
OptionsBuilder<TOptions> służy do konfigurowania TOptions
wystąpień. OptionsBuilder
Usprawnia tworzenie nazwanych opcji, ponieważ jest to tylko jeden parametr do początkowego AddOptions<TOptions>(string optionsName)
wywołania zamiast pojawiać się we wszystkich kolejnych wywołaniach. Opcje weryfikacji i ConfigureOptions
przeciążenia akceptujące zależności usługi są dostępne tylko za pośrednictwem .OptionsBuilder
OptionsBuilder
jest używany w sekcji Walidacja opcji.
Aby uzyskać informacje na temat dodawania repozytorium niestandardowego, zobacz Use AddOptions (Używanie polecenia AddOptions do konfigurowania repozytorium niestandardowego).
Dostęp do usług można uzyskać z iniekcji zależności podczas konfigurowania opcji na dwa sposoby:
Przekaż delegata konfiguracji do Configure adresu w dniu OptionsBuilder<TOptions>. OptionsBuilder<TOptions>
Zapewnia przeciążenia Configure , które umożliwiają korzystanie z maksymalnie pięciu usług do konfigurowania opcji:
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));
Utwórz typ implementujący IConfigureOptions<TOptions> lub IConfigureNamedOptions<TOptions> rejestrujący typ jako usługę.
Zalecamy przekazanie delegata konfiguracji do Configureelementu , ponieważ tworzenie usługi jest bardziej złożone. Tworzenie typu jest równoważne z tym, co robi platforma podczas wywoływania metody Configure. Wywoływanie Configure powoduje zarejestrowanie przejściowego ogólnego IConfigureNamedOptions<TOptions>, który ma konstruktor, który akceptuje określone typy usług ogólnych.
Walidacja opcji umożliwia zweryfikowanie wartości opcji.
Rozważ użycie następującego pliku appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Następująca klasa służy do powiązania z sekcją "MyConfig"
konfiguracji i stosuje kilka DataAnnotations
reguł:
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; }
}
Następujący kod powoduje:
MyConfigOptions
.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();
Metoda rozszerzenia jest definiowana ValidateDataAnnotations
w pakiecie NuGet Microsoft.Extensions.Options.DataAnnotations . W przypadku aplikacji internetowych korzystających z Microsoft.NET.Sdk.Web
zestawu SDK ten pakiet jest odwołuje się niejawnie z udostępnionej platformy.
Poniższy kod wyświetla wartości konfiguracji lub błędy walidacji:
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);
}
Poniższy kod stosuje bardziej złożoną regułę walidacji przy użyciu delegata:
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();
Następująca klasa implementuje IValidateOptions<TOptions>element :
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
umożliwia przeniesienie kodu weryfikacji z Program.cs
klasy i do klasy.
Korzystając z powyższego kodu, walidacja jest włączona przy Program.cs
użyciu następującego kodu:
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();
Walidacja opcji obsługuje również funkcję IValidatableObject. Aby przeprowadzić walidację klasy na poziomie klasy w obrębie samej klasy:
IValidatableObject
interfejs i jego Validate metodę w klasie .Program.cs
.Walidacja opcji jest uruchamiana przy pierwszym utworzeniu TOption
wystąpienia. Oznacza to na przykład, że gdy pierwszy dostęp ma IOptionsSnapshot<TOptions>.Value
miejsce w potoku żądania lub gdy IOptionsMonitor<TOptions>.Get(string)
jest wywoływany w ustawieniach obecnych. Po ponownym załadowaniu ustawień walidacja zostanie uruchomiona ponownie. Środowisko uruchomieniowe ASP.NET Core używa OptionsCache<TOptions> do buforowania wystąpienia opcji po jego utworzeniu.
Aby uruchomić walidację opcji z niecierpliwością, po uruchomieniu aplikacji wywołaj metodę w pliku ValidateOnStart<TOptions>(OptionsBuilder<TOptions>)Program.cs
:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Ustaw konfigurację po konfiguracji za pomocą polecenia IPostConfigureOptions<TOptions>. Po zakończeniu konfiguracji wszystkie IConfigureOptions<TOptions> konfiguracje są uruchamiane:
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 program jest dostępny do po skonfigurowaniu nazwanych opcji:
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();
Użyj PostConfigureAll polecenia , aby po skonfigurowaniu wszystkich wystąpień konfiguracji:
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";
});
Aby uzyskać dostęp do IOptions<TOptions> polecenia lub IOptionsMonitor<TOptions> w Program.cs
usłudze , wywołaj metodę GetRequiredService :WebApplication.Services
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Przez Kirk Larkin i Rick Anderson.
Wzorzec opcji używa klas w celu zapewnienia silnie typizowanego dostępu do grup powiązanych ustawień. Gdy ustawienia konfiguracji są izolowane według scenariusza w oddzielnych klasach, aplikacja jest zgodna z dwoma ważnymi zasadami inżynierii oprogramowania:
Opcje udostępniają również mechanizm sprawdzania poprawności danych konfiguracji. Aby uzyskać więcej informacji, zobacz sekcję Walidacja opcji.
Ten artykuł zawiera informacje na temat wzorca opcji w programie ASP.NET Core. Aby uzyskać informacje na temat używania wzorca opcji w aplikacjach konsoli, zobacz Wzorzec opcji na platformie .NET.
Preferowanym sposobem odczytywania powiązanych wartości konfiguracji jest użycie wzorca opcji. Aby na przykład odczytać następujące wartości konfiguracji:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Utwórz następującą klasę PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; } = String.Empty;
public string Name { get; set; } = String.Empty;
}
Klasa opcji:
Position
nie jest powiązany. Dzięki użyciu pola Position
ciąg "Position"
nie musi być ustalony w aplikacji w przypadku tworzenia powiązania klasy z dostawcą konfiguracji.Następujący kod powoduje:
PositionOptions
z sekcją Position
.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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Element ConfigurationBinder.Get<T>
tworzy powiązanie i zwraca określony typ. Element ConfigurationBinder.Get<T>
może być wygodniejszy w użyciu niż element ConfigurationBinder.Bind
. W poniższym kodzie pokazano sposób użycia elementu ConfigurationBinder.Get<T>
z klasą PositionOptions
:
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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Alternatywne podejście w przypadku korzystania z wzorca opcji to utworzenie powiązania sekcji Position
i dodanie go do kontenera usługi wstrzykiwania zależności. W poniższym kodzie element PositionOptions
jest dodawany do kontenera usługi przy użyciu Configure, a następnie jest tworzone jego powiązanie z konfiguracją:
using ConfigSample.Options;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<PositionOptions>(
builder.Configuration.GetSection(PositionOptions.Position));
var app = builder.Build();
Przy użyciu poprzedniego kodu następujący kod odczytuje opcje położenia:
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}");
}
}
W poprzednim kodzie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji nie są odczytywane. Aby odczytać zmiany po uruchomieniu aplikacji, użyj elementu IOptionsSnapshot.
TOptions
wystąpień.Scenariusze po konfiguracji umożliwiają ustawienie lub zmianę opcji po zakończeniu wszystkich IConfigureOptions<TOptions> konfiguracji.
IOptionsFactory<TOptions> jest odpowiedzialny za tworzenie nowych wystąpień opcji. Ma jedną Create metodę. Domyślna implementacja pobiera wszystkie zarejestrowane IConfigureOptions<TOptions> i IPostConfigureOptions<TOptions> uruchamia najpierw wszystkie konfiguracje, a następnie po konfiguracji. Rozróżnia między elementami IConfigureNamedOptions<TOptions> i IConfigureOptions<TOptions> i wywołuje tylko odpowiedni interfejs.
IOptionsMonitorCache<TOptions> jest używany przez IOptionsMonitor<TOptions> program do buforowania TOptions
wystąpień. Unieważnia IOptionsMonitorCache<TOptions> wystąpienia opcji w monitorze, aby wartość została ponownie skompilowana (TryRemove). Wartości można wprowadzić ręcznie za pomocą TryAddpolecenia . Metoda Clear jest używana, gdy wszystkie nazwane wystąpienia powinny być ponownie tworzone na żądanie.
Za pomocą polecenia IOptionsSnapshot<TOptions>:
Różnica między elementami IOptionsMonitor
i IOptionsSnapshot
polega na tym, że:
IOptionsMonitor
jest usługą Singleton, która w dowolnym momencie pobiera bieżące wartości opcji, co jest szczególnie przydatne w zależnościach pojedynczych.IOptionsSnapshot
jest usługą o określonym zakresie i udostępnia migawkę opcji w momencie IOptionsSnapshot<T>
konstruowania obiektu. Migawki opcji są przeznaczone do użytku z zależnościami przejściowymi i o określonym zakresie.Poniższy kod używa metody 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}");
}
}
Poniższy kod rejestruje wystąpienie konfiguracji, które MyOptions
wiąże się z:
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
W poprzednim kodzie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Poniższy kod rejestruje wystąpienie konfiguracji, które MyOptions
jest powiązane z.
using SampleApp.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.Configure<MyOptions>(
builder.Configuration.GetSection("MyOptions"));
var app = builder.Build();
W poniższym przykładzie użyto metody 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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Nazwane opcje:
Rozważ użycie następującego pliku appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Zamiast tworzyć dwie klasy do powiązania TopItem:Month
i TopItem:Year
, dla każdej sekcji jest używana następująca klasa:
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;
}
Poniższy kod konfiguruje nazwane opcje:
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();
Poniższy kod wyświetla nazwane opcje:
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" );
}
}
Wszystkie opcje są nazwane wystąpienia. IConfigureOptions<TOptions> wystąpienia są traktowane jako docelowe Options.DefaultName
wystąpienie, czyli string.Empty
. IConfigureNamedOptions<TOptions> implementuje IConfigureOptions<TOptions>również funkcję . Domyślna implementacja elementu IOptionsFactory<TOptions> ma logikę do użycia odpowiednio. Nazwana null
opcja służy do określania wartości docelowej wszystkich nazwanych wystąpień zamiast określonego nazwanego wystąpienia. ConfigureAll i PostConfigureAll stosować tę konwencję.
OptionsBuilder<TOptions> służy do konfigurowania TOptions
wystąpień. OptionsBuilder
Usprawnia tworzenie nazwanych opcji, ponieważ jest to tylko jeden parametr do początkowego AddOptions<TOptions>(string optionsName)
wywołania zamiast pojawiać się we wszystkich kolejnych wywołaniach. Opcje weryfikacji i ConfigureOptions
przeciążenia akceptujące zależności usługi są dostępne tylko za pośrednictwem .OptionsBuilder
OptionsBuilder
jest używany w sekcji Walidacja opcji.
Aby uzyskać informacje na temat dodawania repozytorium niestandardowego, zobacz Use AddOptions (Używanie polecenia AddOptions do konfigurowania repozytorium niestandardowego).
Dostęp do usług można uzyskać z iniekcji zależności podczas konfigurowania opcji na dwa sposoby:
Przekaż delegata konfiguracji do Configure adresu w dniu OptionsBuilder<TOptions>. OptionsBuilder<TOptions>
Zapewnia przeciążenia Configure , które umożliwiają korzystanie z maksymalnie pięciu usług do konfigurowania opcji:
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));
Utwórz typ implementujący IConfigureOptions<TOptions> lub IConfigureNamedOptions<TOptions> rejestrujący typ jako usługę.
Zalecamy przekazanie delegata konfiguracji do Configureelementu , ponieważ tworzenie usługi jest bardziej złożone. Tworzenie typu jest równoważne z tym, co robi platforma podczas wywoływania metody Configure. Wywoływanie Configure powoduje zarejestrowanie przejściowego ogólnego IConfigureNamedOptions<TOptions>, który ma konstruktor, który akceptuje określone typy usług ogólnych.
Walidacja opcji umożliwia zweryfikowanie wartości opcji.
Rozważ użycie następującego pliku appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Następująca klasa służy do powiązania z sekcją "MyConfig"
konfiguracji i stosuje kilka DataAnnotations
reguł:
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; }
}
Następujący kod powoduje:
MyConfigOptions
.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();
Metoda rozszerzenia jest definiowana ValidateDataAnnotations
w pakiecie NuGet Microsoft.Extensions.Options.DataAnnotations . W przypadku aplikacji internetowych korzystających z Microsoft.NET.Sdk.Web
zestawu SDK ten pakiet jest odwołuje się niejawnie z udostępnionej platformy.
Poniższy kod wyświetla wartości konfiguracji lub błędy walidacji:
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);
}
Poniższy kod stosuje bardziej złożoną regułę walidacji przy użyciu delegata:
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();
Następująca klasa implementuje IValidateOptions<TOptions>element :
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
umożliwia przeniesienie kodu weryfikacji z Program.cs
klasy i do klasy.
Korzystając z powyższego kodu, walidacja jest włączona przy Program.cs
użyciu następującego kodu:
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();
Walidacja opcji obsługuje również funkcję IValidatableObject. Aby przeprowadzić walidację klasy na poziomie klasy w obrębie samej klasy:
IValidatableObject
interfejs i jego Validate metodę w klasie .Program.cs
.Walidacja opcji jest uruchamiana po raz pierwszy IOptions<TOptions>podczas tworzenia implementacji , IOptionsSnapshot<TOptions>lub IOptionsMonitor<TOptions> . Aby uruchomić walidację opcji z niecierpliwością, po uruchomieniu aplikacji wywołaj metodę w pliku ValidateOnStart Program.cs
:
builder.Services.AddOptions<MyConfigOptions>()
.Bind(builder.Configuration.GetSection(MyConfigOptions.MyConfig))
.ValidateDataAnnotations()
.ValidateOnStart();
Ustaw konfigurację po konfiguracji za pomocą polecenia IPostConfigureOptions<TOptions>. Po zakończeniu konfiguracji wszystkie IConfigureOptions<TOptions> konfiguracje są uruchamiane:
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 program jest dostępny do po skonfigurowaniu nazwanych opcji:
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();
Użyj PostConfigureAll polecenia , aby po skonfigurowaniu wszystkich wystąpień konfiguracji:
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";
});
Aby uzyskać dostęp do IOptions<TOptions> polecenia lub IOptionsMonitor<TOptions> w Program.cs
usłudze , wywołaj metodę GetRequiredService :WebApplication.Services
var app = builder.Build();
var option1 = app.Services.GetRequiredService<IOptionsMonitor<MyOptions>>()
.CurrentValue.Option1;
Przez Kirk Larkin i Rick Anderson.
Wzorzec opcji używa klas w celu zapewnienia silnie typizowanego dostępu do grup powiązanych ustawień. Gdy ustawienia konfiguracji są izolowane według scenariusza w oddzielnych klasach, aplikacja jest zgodna z dwoma ważnymi zasadami inżynierii oprogramowania:
Opcje udostępniają również mechanizm sprawdzania poprawności danych konfiguracji. Aby uzyskać więcej informacji, zobacz sekcję Walidacja opcji.
Ten temat zawiera informacje na temat wzorca opcji w programie ASP.NET Core. Aby uzyskać informacje na temat używania wzorca opcji w aplikacjach konsoli, zobacz Wzorzec opcji na platformie .NET.
Wyświetl lub pobierz przykładowy kod (jak pobrać)
Preferowanym sposobem odczytywania powiązanych wartości konfiguracji jest użycie wzorca opcji. Aby na przykład odczytać następujące wartości konfiguracji:
"Position": {
"Title": "Editor",
"Name": "Joe Smith"
}
Utwórz następującą klasę PositionOptions
:
public class PositionOptions
{
public const string Position = "Position";
public string Title { get; set; }
public string Name { get; set; }
}
Klasa opcji:
Position
nie jest powiązany. Dzięki użyciu właściwości Position
ciąg "Position"
nie musi być ustalony w aplikacji w przypadku tworzenia powiązania klasy z dostawcą konfiguracji.Następujący kod powoduje:
PositionOptions
z sekcją Position
.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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Element ConfigurationBinder.Get<T>
tworzy powiązanie i zwraca określony typ. Element ConfigurationBinder.Get<T>
może być wygodniejszy w użyciu niż element ConfigurationBinder.Bind
. W poniższym kodzie pokazano sposób użycia elementu ConfigurationBinder.Get<T>
z klasą PositionOptions
:
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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Alternatywne podejście w przypadku korzystania z wzorca opcji to utworzenie powiązania sekcji Position
i dodanie go do kontenera usługi wstrzykiwania zależności. W poniższym kodzie element PositionOptions
jest dodawany do kontenera usługi przy użyciu Configure, a następnie jest tworzone jego powiązanie z konfiguracją:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<PositionOptions>(Configuration.GetSection(
PositionOptions.Position));
services.AddRazorPages();
}
Przy użyciu poprzedniego kodu następujący kod odczytuje opcje położenia:
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}");
}
}
W poprzednim kodzie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji nie są odczytywane. Aby odczytać zmiany po uruchomieniu aplikacji, użyj elementu IOptionsSnapshot.
TOptions
wystąpień.Scenariusze po konfiguracji umożliwiają ustawienie lub zmianę opcji po zakończeniu wszystkich IConfigureOptions<TOptions> konfiguracji.
IOptionsFactory<TOptions> jest odpowiedzialny za tworzenie nowych wystąpień opcji. Ma jedną Create metodę. Domyślna implementacja pobiera wszystkie zarejestrowane IConfigureOptions<TOptions> i IPostConfigureOptions<TOptions> uruchamia najpierw wszystkie konfiguracje, a następnie po konfiguracji. Rozróżnia między elementami IConfigureNamedOptions<TOptions> i IConfigureOptions<TOptions> i wywołuje tylko odpowiedni interfejs.
IOptionsMonitorCache<TOptions> jest używany przez IOptionsMonitor<TOptions> program do buforowania TOptions
wystąpień. Unieważnia IOptionsMonitorCache<TOptions> wystąpienia opcji w monitorze, aby wartość została ponownie skompilowana (TryRemove). Wartości można wprowadzić ręcznie za pomocą TryAddpolecenia . Metoda Clear jest używana, gdy wszystkie nazwane wystąpienia powinny być ponownie tworzone na żądanie.
Przy użyciu IOptionsSnapshot<TOptions>opcji opcje są obliczane raz na żądanie w przypadku uzyskania dostępu do żądania i buforowania przez okres istnienia żądania. Zmiany konfiguracji są odczytywane po uruchomieniu aplikacji podczas korzystania z dostawców konfiguracji obsługujących odczytywanie zaktualizowanych wartości konfiguracji.
Różnica między elementami IOptionsMonitor
i IOptionsSnapshot
polega na tym, że:
IOptionsMonitor
jest usługą Singleton, która w dowolnym momencie pobiera bieżące wartości opcji, co jest szczególnie przydatne w zależnościach pojedynczych.IOptionsSnapshot
jest usługą o określonym zakresie i udostępnia migawkę opcji w momencie IOptionsSnapshot<T>
konstruowania obiektu. Migawki opcji są przeznaczone do użytku z zależnościami przejściowymi i o określonym zakresie.Poniższy kod używa metody 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}");
}
}
Poniższy kod rejestruje wystąpienie konfiguracji, które MyOptions
wiąże się z:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
W poprzednim kodzie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Poniższy kod rejestruje wystąpienie konfiguracji, które MyOptions
jest powiązane z.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddRazorPages();
}
W poniższym przykładzie użyto metody 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}");
}
}
W poprzednim kodzie domyślnie zmiany w pliku konfiguracji JSON po uruchomieniu aplikacji są odczytywane.
Nazwane opcje:
Rozważ użycie następującego pliku appsettings.json
:
{
"TopItem": {
"Month": {
"Name": "Green Widget",
"Model": "GW46"
},
"Year": {
"Name": "Orange Gadget",
"Model": "OG35"
}
}
}
Zamiast tworzyć dwie klasy do powiązania TopItem:Month
i TopItem:Year
, dla każdej sekcji jest używana następująca klasa:
public class TopItemSettings
{
public const string Month = "Month";
public const string Year = "Year";
public string Name { get; set; }
public string Model { get; set; }
}
Poniższy kod konfiguruje nazwane opcje:
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();
}
Poniższy kod wyświetla nazwane opcje:
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" );
}
}
Wszystkie opcje są nazwane wystąpienia. IConfigureOptions<TOptions> wystąpienia są traktowane jako docelowe Options.DefaultName
wystąpienie, czyli string.Empty
. IConfigureNamedOptions<TOptions> implementuje IConfigureOptions<TOptions>również funkcję . Domyślna implementacja elementu IOptionsFactory<TOptions> ma logikę do użycia odpowiednio. Nazwana null
opcja służy do określania wartości docelowej wszystkich nazwanych wystąpień zamiast określonego nazwanego wystąpienia. ConfigureAll i PostConfigureAll stosować tę konwencję.
OptionsBuilder<TOptions> służy do konfigurowania TOptions
wystąpień. OptionsBuilder
Usprawnia tworzenie nazwanych opcji, ponieważ jest to tylko jeden parametr do początkowego AddOptions<TOptions>(string optionsName)
wywołania zamiast pojawiać się we wszystkich kolejnych wywołaniach. Opcje weryfikacji i ConfigureOptions
przeciążenia akceptujące zależności usługi są dostępne tylko za pośrednictwem .OptionsBuilder
OptionsBuilder
jest używany w sekcji Walidacja opcji.
Aby uzyskać informacje na temat dodawania repozytorium niestandardowego, zobacz Use AddOptions (Używanie polecenia AddOptions do konfigurowania repozytorium niestandardowego).
Dostęp do usług można uzyskać z iniekcji zależności podczas konfigurowania opcji na dwa sposoby:
Przekaż delegata konfiguracji do Configure adresu w dniu OptionsBuilder<TOptions>. OptionsBuilder<TOptions>
Zapewnia przeciążenia Configure , które umożliwiają korzystanie z maksymalnie pięciu usług do konfigurowania opcji:
services.AddOptions<MyOptions>("optionalName")
.Configure<Service1, Service2, Service3, Service4, Service5>(
(o, s, s2, s3, s4, s5) =>
o.Property = DoSomethingWith(s, s2, s3, s4, s5));
Utwórz typ implementujący IConfigureOptions<TOptions> lub IConfigureNamedOptions<TOptions> rejestrujący typ jako usługę.
Zalecamy przekazanie delegata konfiguracji do Configureelementu , ponieważ tworzenie usługi jest bardziej złożone. Tworzenie typu jest równoważne z tym, co robi platforma podczas wywoływania metody Configure. Wywoływanie Configure powoduje zarejestrowanie przejściowego ogólnego IConfigureNamedOptions<TOptions>, który ma konstruktor, który akceptuje określone typy usług ogólnych.
Walidacja opcji umożliwia zweryfikowanie wartości opcji.
Rozważ użycie następującego pliku appsettings.json
:
{
"MyConfig": {
"Key1": "My Key One",
"Key2": 10,
"Key3": 32
}
}
Następująca klasa wiąże się z sekcją "MyConfig"
konfiguracji i stosuje kilka DataAnnotations
reguł:
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; }
}
Następujący kod powoduje:
MyConfigOptions
.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();
}
Metoda rozszerzenia jest definiowana ValidateDataAnnotations
w pakiecie NuGet Microsoft.Extensions.Options.DataAnnotations . W przypadku aplikacji internetowych korzystających z Microsoft.NET.Sdk.Web
zestawu SDK ten pakiet jest odwołuje się niejawnie z udostępnionej platformy.
Poniższy kod wyświetla wartości konfiguracji lub błędy walidacji:
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);
}
Poniższy kod stosuje bardziej złożoną regułę walidacji przy użyciu delegata:
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();
}
Następująca klasa implementuje IValidateOptions<TOptions>element :
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
umożliwia przeniesienie kodu weryfikacji z StartUp
klasy i do klasy.
Korzystając z powyższego kodu, walidacja jest włączona przy Startup.ConfigureServices
użyciu następującego kodu:
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MyConfigOptions>(Configuration.GetSection(
MyConfigOptions.MyConfig));
services.TryAddEnumerable(ServiceDescriptor.Singleton<IValidateOptions
<MyConfigOptions>, MyConfigValidation>());
services.AddControllersWithViews();
}
Ustaw konfigurację po konfiguracji za pomocą polecenia IPostConfigureOptions<TOptions>. Po zakończeniu konfiguracji wszystkie IConfigureOptions<TOptions> konfiguracje są uruchamiane:
services.PostConfigure<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
PostConfigure program jest dostępny do po skonfigurowaniu nazwanych opcji:
services.PostConfigure<MyOptions>("named_options_1", myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
Użyj PostConfigureAll polecenia , aby po skonfigurowaniu wszystkich wystąpień konfiguracji:
services.PostConfigureAll<MyOptions>(myOptions =>
{
myOptions.Option1 = "post_configured_option1_value";
});
IOptions<TOptions> i IOptionsMonitor<TOptions> może być używany w programie Startup.Configure
, ponieważ usługi są tworzone przed wykonaniem Configure
metody.
public void Configure(IApplicationBuilder app,
IOptionsMonitor<MyOptions> optionsAccessor)
{
var option1 = optionsAccessor.CurrentValue.Option1;
}
Nie używaj ani IOptions<TOptions> IOptionsMonitor<TOptions> w elemecie Startup.ConfigureServices
. Może istnieć niespójny stan opcji ze względu na kolejność rejestracji usług.
Pakiet Microsoft.Extensions.Options.ConfigurationExtensions jest niejawnie przywołyny w aplikacjach ASP.NET Core.
Opinia o produkcie ASP.NET Core
ASP.NET Core to projekt typu open source. Wybierz link, aby przekazać opinię:
Zdarzenia
Power BI DataViz World Championships
14 lut, 16 - 31 mar, 16
Z 4 szans na wejście, można wygrać pakiet konferencji i zrobić go do LIVE Grand Finale w Las Vegas
Dowiedz się więcej