.NET'te seçenekler deseni
Seçenekler düzeni, ilgili ayar gruplarına kesin olarak türü kesin olarak yazarak erişim sağlamak için sınıfları kullanır. Yapılandırma ayarları senaryoya göre ayrı sınıflara yalıtılmışsa, uygulama iki önemli yazılım mühendisliği ilkesine uyar:
- Arabirim Ayrımı İlkesi (ISS)veya Kapsülleme: Yapılandırma ayarlarına bağlı senaryolar (sınıflar) yalnızca kendi kullanımları yapılandırma ayarlarına bağlıdır.
- Endişelerin Ayrımı:Ayarlar farklı bölümlerinin birbirine bağımlı veya birbirine bağlı olmadığını varsayabilirsiniz.
Seçenekler ayrıca yapılandırma verilerini doğrulamak için bir mekanizma sağlar. Daha fazla bilgi için Seçenekler doğrulama bölümüne bakın.
Bağlama hiyerarşik yapılandırması
İlgili yapılandırma değerlerini okumanın tercih edilen yolu seçenekler desenini kullanmaktır. Seçenekler deseni, genel tür IOptions<TOptions> parametresinin ile kısıtlanmış TOptions olduğu arabirim aracılığıyla class mümkündür. daha IOptions<TOptions> sonra bağımlılık ekleme ile sağlanmalıdır. Daha fazla bilgi için bkz. .NET'te bağımlılık ekleme.
Örneğin, aşağıdaki yapılandırma değerlerini okumak için:
"TransientFaultHandlingOptions": {
"Enabled": true,
"AutoRetryDelay": "00:00:07"
},
Aşağıdaki sınıfı TransientFaultHandlingOptions oluşturun:
public class TransientFaultHandlingOptions
{
public bool Enabled { get; set; }
public TimeSpan AutoRetryDelay { get; set; }
}
Seçenekler desenini kullanırken bir options sınıfı:
- Genel parametresiz oluşturucu ile soyut olmayan olmalıdır
- Bağlamak için genel okuma-yazma özellikleri içerir (alanlar bağlı değildir)
Aşağıdaki kod:
- Sınıfını bölümüne bağlamak için ConfigurationBinder.Bind'i
TransientFaultHandlingOptions"TransientFaultHandlingOptions"arar. - Yapılandırma verilerini görüntüler.
IConfigurationRoot configurationRoot = configuration.Build();
TransientFaultHandlingOptions options = new();
configurationRoot.GetSection(nameof(TransientFaultHandlingOptions))
.Bind(options);
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
Önceki kodda, uygulama başlatıldıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.
ConfigurationBinder.Get<T> belirtilen türü bağlar ve döndürür. ConfigurationBinder.Get<T> kullanmaktan daha kullanışlı ConfigurationBinder.Bind olabilir. Aşağıdaki kod, sınıfıyla nasıl ConfigurationBinder.Get<T> kullanabileceğini TransientFaultHandlingOptions gösterir:
IConfigurationRoot configurationRoot = configuration.Build();
var options =
configurationRoot.GetSection(nameof(TransientFaultHandlingOptions))
.Get<TransientFaultHandlingOptions>();
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
Önceki kodda, uygulama başlatıldıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.
Önemli
sınıfı ConfigurationBinder gibi ve ile kısıtlanmış çeşitli .Bind(object instance) .Get<T>() API'leri ortaya class çıkarır. Seçenekler arabirimlerinin herhangi birini kullanırken,daha önce anılan seçenekler sınıfı kısıtlamalarına uymanız gerekir.
Seçenekler deseni kullanılırken alternatif bir yaklaşım bölümü bağlamak ve bağımlılık ekleme hizmeti "TransientFaultHandlingOptions" kapsayıcısı eklemektir. Aşağıdaki kodda, TransientFaultHandlingOptions ile hizmet kapsayıcısı eklenir ve Configure yapılandırmaya bağlıdır:
services.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
key: nameof(TransientFaultHandlingOptions)));
hem hem de services configurationRoot nesnelerine erişmek için özelliği olarak ConfigureServices kullanılabilir yöntemini — IConfiguration HostBuilderContext.Configuration kullanabilirsiniz.
Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
var configurationRoot = context.Configuration;
services.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(nameof(TransientFaultHandlingOptions)));
});
İpucu
keyparametresi, aranan yapılandırma bölümünün adıdır. Temsil eden türün adıyla eşleşmesi gerek değildir. Örneğin adlı bir bölümünüz "FaultHandling" olabilir ve bu bölüm sınıfı tarafından temsil TransientFaultHandlingOptions olabilir. Bu örnekte bunun yerine "FaultHandling" işlevine GetSection geçersiniz. nameofİşleç, adlandırılmış bölüm karşılık gelen türle eşlediği zaman kolaylık sağlamak için kullanılır.
Yukarıdaki kodu kullanarak aşağıdaki kod konum seçeneklerini okur:
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public class ExampleService
{
private readonly TransientFaultHandlingOptions _options;
public ExampleService(IOptions<TransientFaultHandlingOptions> options) =>
_options = options.Value;
public void DisplayValues()
{
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={_options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={_options.AutoRetryDelay}");
}
}
Önceki kodda, uygulama başlatıldıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunmaz. Uygulama başlatıldıktan sonra değişiklikleri okumak için IOptionsSnapshot kullanın.
Seçenekler arabirimleri
- Şunları desteklemez:
- Uygulama başlatıldıktan sonra yapılandırma verilerini okuma.
- Adlandırılmış seçenekler
- Bir Singleton olarak kaydedilir ve herhangi bir hizmet ömrüne edilebilir.
- Seçeneklerin kapsamlı veya geçici yaşam süreleri içinde her ekleme çözünürlüğünde yeniden yeniden derlemesi gereken senaryolarda yararlıdır. Daha fazla bilgi için bkz. Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma.
- Kapsamı Kapsamlı olarak kaydedilir ve bu nedenle bir Singleton hizmetine ekleme olamaz.
- Adlandırılmış seçenekleri destekler
- Örnekler için seçenekleri almak ve seçenek bildirimlerini yönetmek
TOptionsiçin kullanılır. - Bir Singleton olarak kaydedilir ve herhangi bir hizmet ömrüne edilebilir.
- Destekle -yen:
- Bildirimleri değiştirme
- Adlandırılmış seçenekler
- Yeniden yüklenebilir yapılandırma
- Seçmeli seçenekleri geçersiz kılınma ( IOptionsMonitorCache<TOptions> )
IOptionsFactory<TOptions> , yeni seçenek örnekleri oluşturmakla sorumludur. Tek bir yöntemi Create vardır. Varsayılan uygulama tüm kayıtlı yapılandırmaları alır ve önce tüm IConfigureOptions<TOptions> IPostConfigureOptions<TOptions> yapılandırmaları çalıştırır ve ardından yapılandırma sonrası gelir. ile arasında ayrım IConfigureNamedOptions<TOptions> yapmak için yalnızca uygun arabirimi IConfigureOptions<TOptions> çağıran bir uygulamadır.
IOptionsMonitorCache<TOptions> , örnekleri IOptionsMonitor<TOptions> önbelleğe etmek TOptions için tarafından kullanılır. , değerin yeniden işleniyor ( ) için izleyicide seçenek IOptionsMonitorCache<TOptions> örneklerini geçersiz hale TryRemove gelir. Değerler ile el ile TryAdd tanıtılabilir. yöntemi, Clear tüm adlandırılmış örneklerin isteğe bağlı olarak yeniden oluşturulması gerektiği durumlarda kullanılır.
Seçenek arabirimleri avantajları
Genel bir sarmalayıcı türü kullanmak, seçeneğin ömrünü DI kapsayıcısı ile bağımsız olarak çözmenizi sağlar. Arabirim, IOptions<TOptions>.Value seçenek türünüz üzerinde genel kısıtlamalar da dahil olmak üzere bir soyutlama katmanı sağlar. Bu, aşağıdaki avantajları sağlar:
- Yapılandırma örneğinin
Tdeğerlendirmesi, ekleme yerine IOptions<TOptions>.Value erişimine ertelenmiştir. Bu önemlidir çünkü seçeneğini çeşitli yerlerden tüketebilirsiniz ve hakkında hiçbir şey değiştirmeden yaşamTsüresi semantiğiTseçebilirsiniz. - türünde seçenekleri
Tkaydettirerek, türü açıkça kaydetmenizTgerekmez. Basit varsayılanlarla bir kitaplık yazarken ve çağıranı belirli bir yaşam süresine sahip DI kapsayıcısı seçenekleri kaydetmeye zorlamak istemeyebilirsiniz. - API'nin perspektifinden bakıldığında, tür üzerinde kısıtlamalara izin verir
T(bu durumda,Tbir başvuru türüyle sınırlandırıldı).
Güncelleştirilmiş verileri okumak için IOptionsSnapshot kullanma
'i kullanırken, seçenekler erişilirken istek başına bir kez hesaplanır ve IOptionsSnapshot<TOptions> isteğin ömrü boyunca önbelleğe alınmış olur. Yapılandırmada yapılan değişiklikler, güncelleştirilmiş yapılandırma değerlerini okumayı destekleyen yapılandırma sağlayıcıları kullanılırken uygulama başladıktan sonra okunur.
ile arasındaki IOptionsMonitor fark IOptionsSnapshot şudur:
IOptionsMonitor, geçerli seçenek değerlerini her zaman alan ve özellikle tekli bağımlılıklarda yararlı olan tekli bir hizmettir.IOptionsSnapshotkapsamlı bir hizmettir ve nesnenin oluşturulurken seçeneklerin anlıkIOptionsSnapshot<T>görüntüsünü sağlar. Seçenekler anlık görüntüleri, geçici ve kapsamlı bağımlılıklarla kullanım için tasarlanmıştır.
Aşağıdaki kod IOptionsSnapshot<TOptions> kullanır.
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public class ScopedService
{
private readonly TransientFaultHandlingOptions _options;
public ScopedService(IOptionsSnapshot<TransientFaultHandlingOptions> options) =>
_options = options.Value;
public void DisplayValues()
{
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={_options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={_options.AutoRetryDelay}");
}
}
Aşağıdaki kod, aşağıdakilere bağlanan bir TransientFaultHandlingOptions yapılandırma örneğini kaydettirmektedir:
services.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
nameof(TransientFaultHandlingOptions)));
Önceki kodda, uygulama başlatıldıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.
IOptionsMonitor
Aşağıdaki kod, bağlaması yapılan bir yapılandırma TransientFaultHandlingOptions örneğini kaydettirmektedir.
services.Configure<TransientFaultHandlingOptions>(
configurationRoot.GetSection(
nameof(TransientFaultHandlingOptions)));
Aşağıdaki örnekte IOptionsMonitor<TOptions> kullanır:
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public class MonitorService
{
private readonly IOptionsMonitor<TransientFaultHandlingOptions> _monitor;
public MonitorService(IOptionsMonitor<TransientFaultHandlingOptions> monitor) =>
_monitor = monitor;
public void DisplayValues()
{
TransientFaultHandlingOptions options = _monitor.CurrentValue;
Console.WriteLine($"TransientFaultHandlingOptions.Enabled={options.Enabled}");
Console.WriteLine($"TransientFaultHandlingOptions.AutoRetryDelay={options.AutoRetryDelay}");
}
}
Önceki kodda, uygulama başlatıldıktan sonra JSON yapılandırma dosyasında yapılan değişiklikler okunur.
İpucu
Docker kapsayıcıları ve ağ paylaşımları gibi bazı dosya sistemleri, değişiklik bildirimlerini güvenilir bir şekilde gönderemeyebilirsiniz. Bu ortamlarda IOptionsMonitor<TOptions> arabirimini kullanırken, dosya sistemini değişiklikler için yoklama yapmak için ortam DOTNET_USE_POLLING_FILE_WATCHER 1 true değişkenlerini veya olarak ayarlayın. Değişikliklerin yoklama aralığı dört saniyede birdir ve yapılandırılabilir değildir.
Docker kapsayıcıları hakkında daha fazla bilgi için bkz. .NET uygulamasını kapsayıcılı hale uygulama.
IConfigureNamedOptions kullanarak adlandırılmış seçenekler desteği
Adlandırılmış seçenekler:
- Birden çok yapılandırma bölümü aynı özelliklere bağlı olduğunda yararlıdır.
- Büyük/büyük/büyük harfe duyarlıdır.
Aşağıdaki appsettings.json dosyasını göz önünde bulundurabilirsiniz:
{
"Features": {
"Personalize": {
"Enabled": true,
"ApiKey": "aGEgaGEgeW91IHRob3VnaHQgdGhhdCB3YXMgcmVhbGx5IHNvbWV0aGluZw=="
},
"WeatherStation": {
"Enabled": true,
"ApiKey": "QXJlIHlvdSBhdHRlbXB0aW5nIHRvIGhhY2sgdXM/"
}
}
}
ve bağlamak için iki sınıf oluşturmak Features:Personalize Features:WeatherStation yerine, her bölüm için aşağıdaki sınıf kullanılır:
public class Features
{
public const string Personalize = nameof(Personalize);
public const string WeatherStation = nameof(WeatherStation);
public bool Enabled { get; set; }
public string ApiKey { get; set; }
}
Aşağıdaki kod adlandırılmış seçenekleri yapılandırıyor:
ConfigureServices(services =>
{
services.Configure<Features>(
Features.Personalize,
Configuration.GetSection("Features:Personalize"));
services.Configure<Features>(
Features.WeatherStation,
Configuration.GetSection("Features:WeatherStation"));
});
Aşağıdaki kod adlandırılmış seçenekleri görüntüler:
public class Service
{
private readonly Features _personalizeFeature;
private readonly Features _weatherStationFeature;
public Service(IOptionsSnapshot<Features> namedOptionsAccessor)
{
_personalizeFeature = namedOptionsAccessor.Get(Features.Personalize);
_weatherStationFeature = namedOptionsAccessor.Get(Features.WeatherStation);
}
}
Tüm seçenekler adlandırılmış örneklerdir. IConfigureOptions<TOptions> örnekler, örneği hedefleme olarak kabul Options.DefaultName edilir ve bu da string.Empty olur. IConfigureNamedOptions<TOptions> ayrıca , 'i de uygulayan IConfigureOptions<TOptions> bir uygulamadır. Varsayılan uygulamasının her biri IOptionsFactory<TOptions> uygun şekilde kullanma mantığı vardır. Adlandırılmış null seçenek, belirli bir adlandırılmış örnek yerine tüm adlandırılmış örnekleri hedeflemek için kullanılır. ConfigureAll ve PostConfigureAll bu kuralı kullanın.
OptionsBuilder API'si
OptionsBuilder<TOptions> örnekleri yapılandırmak TOptions için kullanılır. OptionsBuilder , sonraki tüm çağrılarda görünmek yerine ilk çağrının yalnızca tek bir parametresi olduğu için AddOptions<TOptions>(string optionsName) adlandırılmış seçeneklerin oluşturulmasını kolaylaştırıyor. Seçenek doğrulama ve ConfigureOptions hizmet bağımlılıklarını kabul eden aşırı yüklemeler yalnızca aracılığıyla OptionsBuilder kullanılabilir.
OptionsBuilder , Seçenekler doğrulama bölümünde kullanılır.
Seçenekleri yapılandırmak için DI hizmetlerini kullanma
Seçenekler iki şekilde yapılandırırken hizmetlere bağımlılık eklemeden erişilebilir:
Bir yapılandırma temsilcisini OptionsBuilder'da Yapılandır'a ilenin. <TOptions>
OptionsBuilder<TOptions>, seçenekleri yapılandırmak için en fazla beş hizmet kullanımına izin veren Yapılandırma aşırı yüklemeleri sağlar:services.AddOptions<MyOptions>("optionalName") .Configure<ExampleService, ScopedService, MonitorService>( (options, es, ss, ms) => options.Property = DoSomethingWith(es, ss, ms));veya uygulayan bir IConfigureOptions<TOptions> tür oluşturun ve türü hizmet olarak IConfigureNamedOptions<TOptions> kaydedin.
Bir hizmet oluşturmak daha karmaşık olduğu için yapılandırmatemsilcisini Yapılandırma'ya geçirmenizi öneririz. Tür oluşturmak, Yapılandır'ı çağıran çerçevenin ne yaptığına eşdeğerdir. Configure çağrısı, belirtilen genel hizmet türlerini kabul IConfigureNamedOptions<TOptions> eden bir oluşturucuya sahip olan geçici bir genel 'i kaydettirmektedir.
Seçenek doğrulama
Seçenek doğrulaması, seçenek değerlerinin doğrulanmasına olanak sağlar.
Aşağıdaki appsettings.json dosyasını göz önünde bulundurabilirsiniz:
{
"MyCustomSettingsSection": {
"SiteTitle": "Amazing docs from Awesome people!",
"Scale": 10,
"VerbosityLevel": 32
}
}
Aşağıdaki sınıf yapılandırma bölümüne "MyCustomSettingsSection" bağlar ve birkaç kural DataAnnotations uygular:
using System.ComponentModel.DataAnnotations;
namespace ConsoleJson.Example;
public class SettingsOptions
{
public const string ConfigurationSectionName = "MyCustomSettingsSection";
[RegularExpression(@"^[a-zA-Z''-'\s]{1,40}$")]
public string SiteTitle { get; set; } = null!;
[Range(0, 1000,
ErrorMessage = "Value for {0} must be between {1} and {2}.")]
public int Scale { get; set; }
public int VerbosityLevel { get; set; }
}
Yukarıdaki SettingsOptions sınıfta, özelliği ConfigurationSectionName bağlan için yapılandırma bölümünün adını içerir. Bu senaryoda options nesnesi yapılandırma bölümünün adını sağlar.
İpucu
Yapılandırma bölümü adı, bağlaması yapılan yapılandırma nesnesine göre bağımsızdır. Başka bir deyişle adlı bir yapılandırma "FooBarOptions" bölümü, adlı bir options nesnesine bağlı ZedOptions olabilir. Bunları aynı şekilde adlandırarak yapmak yaygın olsa da gerekli değildir ve aslında ad çakışmalarına neden olabilir.
Aşağıdaki kod:
- sınıfına AddOptions bağlı bir <TOptions> OptionsBuilder almak için
SettingsOptionsçağrıları. - kullanarak ValidateDataAnnotations doğrulamayı etkinleştirmek için
DataAnnotationsçağrıları.
services.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations();
Uzantı ValidateDataAnnotations yöntemi, Microsoft.Extensions.Options.DataAnnotations NuGet tanımlanır.
Aşağıdaki kod yapılandırma değerlerini veya doğrulama hatalarını görüntüler:
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
public class ValidationService
{
private readonly ILogger<ValidationService> _logger;
private readonly IOptions<SettingsOptions> _config;
public ValidationService(
ILogger<ValidationService> logger,
IOptions<SettingsOptions> config)
{
_config = config;
_logger = logger;
try
{
SettingsOptions options = _config.Value;
}
catch (OptionsValidationException ex)
{
foreach (string failure in ex.Failures)
{
_logger.LogError(failure);
}
}
}
}
Aşağıdaki kod, temsilci kullanarak daha karmaşık bir doğrulama kuralı uygular:
services.AddOptions<SettingsOptions>()
.Bind(Configuration.GetSection(SettingsOptions.ConfigurationSectionName))
.ValidateDataAnnotations()
.Validate(config =>
{
if (config.Scale != 0)
{
return config.VerbosityLevel > config.Scale;
}
return true;
}, "VerbosityLevel must be > than Scale.");
Karmaşık doğrulama için IValidateOptions
Aşağıdaki sınıf IValidateOptions<TOptions> uygulayan:
using System.Text.RegularExpressions;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
namespace ConsoleJson.Example;
class ValidateSettingsOptions : IValidateOptions<SettingsOptions>
{
public SettingsOptions _settings { get; private set; }
public ValidateSettingsOptions(IConfiguration config) =>
_settings = config.GetSection(SettingsOptions.ConfigurationSectionName)
.Get<SettingsOptions>();
public ValidateOptionsResult Validate(string name, SettingsOptions options)
{
string result = "";
var rx = new Regex(@"^[a-zA-Z''-'\s]{1,40}$");
Match match = rx.Match(options.SiteTitle);
if (string.IsNullOrEmpty(match.Value))
{
result += $"{options.SiteTitle} doesn't match RegEx\n";
}
if (options.Scale < 0 || options.Scale > 1000)
{
result += $"{options.Scale} isn't within Range 0 - 1000\n";
}
if (_settings.Scale is 0 && _settings.VerbosityLevel <= _settings.Scale)
{
result += "VerbosityLevel must be > than Scale.";
}
return result != null
? ValidateOptionsResult.Fail(result)
: ValidateOptionsResult.Success;
}
}
IValidateOptions doğrulama kodunun bir sınıfa taşınmasını sağlar.
Yukarıdaki kod kullanılarak, içinde aşağıdaki ConfigureServices kodla doğrulama etkinleştirilir:
services.Configure<SettingsOptions>(
Configuration.GetSection(
SettingsOptions.ConfigurationSectionName));
services.TryAddEnumerable(
ServiceDescriptor.Singleton
<IValidateOptions<SettingsOptions>, ValidateSettingsOptions>());
Yapılandırma sonrası seçenekler
ile yapılandırma sonrası IPostConfigureOptions<TOptions> ayarlama. Yapılandırma sonrası tüm yapılandırmalar olduktan sonra çalışır ve yapılandırmayı geçersiz kılmanız IConfigureOptions<TOptions> gereken senaryolarda yararlı olabilir:
services.PostConfigure<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
PostConfigure adlandırılmış seçenekleri yapılandırma sonrası için kullanılabilir:
services.PostConfigure<CustomOptions>("named_options_1", customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});
Tüm PostConfigureAll yapılandırma örneklerini post-configure için kullanın:
services.PostConfigureAll<CustomOptions>(customOptions =>
{
customOptions.Option1 = "post_configured_option1_value";
});