Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
С помощью внедрения зависимостей можно использовать шаблон параметров для регистрации служб и их соответствующих конфигураций. Шаблон параметров позволяет пользователям вашей библиотеки (и ваших услуг) требовать экземпляры интерфейсов параметров, в котором является вашим классом параметров. Использование параметров конфигурации с помощью строго типизированных объектов помогает обеспечить согласованное представление значений, обеспечивает проверку с заметками данных и удаляет нагрузку на анализ строковых значений вручную. Существует множество поставщиков конфигурации для пользователей библиотеки. С помощью этих поставщиков потребители могут настраивать библиотеку различными способами.
Как автор библиотеки .NET вы узнаете, как правильно предоставлять шаблон параметров потребителям библиотеки. Существуют различные способы достижения одного и того же, и несколько рекомендаций.
Соглашения об именах
По соглашению методы расширения, ответственные за регистрацию служб, называются Add{Service}, где {Service} — значимое и описательное имя.
Add{Service} Методы расширения являются обычными в ASP.NET Core и .NET.
✔️ РАССМОТРИТЕ имена, которые различают вашу услугу от других предложений.
❌ Не используйте имена, которые уже являются частью экосистемы .NET из официальных пакетов Майкрософт.
✔️ Рекомендуется именовать статические классы, предоставляющие методы расширения, как {Type}Extensions, где {Type} — это тип, который вы расширяете.
Руководство по пространству имен
Пакеты Майкрософт используют пространство имен Microsoft.Extensions.DependencyInjection для объединения регистрации различных предложений услуг.
✔️ РАССМОТРИТЕ пространство имен, которое четко идентифицирует ваше пакетное предложение.
❌ Не используйте Microsoft.Extensions.DependencyInjection пространство имен для не официальных пакетов Майкрософт.
Без параметров
Если служба может работать с минимальной или без явной конфигурации, рассмотрите метод расширения без параметров.
using Microsoft.Extensions.DependencyInjection;
namespace ExampleLibrary.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyLibraryService(
this IServiceCollection services)
{
services.AddOptions<LibraryOptions>()
.Configure(options =>
{
// Specify default option values
});
// Register lib services here...
// services.AddScoped<ILibraryService, DefaultLibraryService>();
return services;
}
}
В предыдущем коде элемент AddMyLibraryService:
- Расширяет экземпляр IServiceCollection
- Вызовы OptionsServiceCollectionExtensions.AddOptions<TOptions>(IServiceCollection) с параметром типа
LibraryOptions - Цепочка вызова Configure, которая указывает значения параметров по умолчанию.
IConfiguration параметр
При создании библиотеки, которая предоставляет множество вариантов потребителям, может потребоваться использовать IConfiguration метод расширения параметров. Ожидаемый IConfiguration экземпляр должен быть ограничен именованным разделом конфигурации с помощью IConfiguration.GetSection функции.
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace ExampleLibrary.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyLibraryService(
this IServiceCollection services,
IConfiguration namedConfigurationSection)
{
// Default library options are overridden
// by bound configuration values.
services.Configure<LibraryOptions>(namedConfigurationSection);
// Register lib services here...
// services.AddScoped<ILibraryService, DefaultLibraryService>();
return services;
}
}
Подсказка
Метод Configure<TOptions>(IServiceCollection, IConfiguration) является частью Microsoft.Extensions.Options.ConfigurationExtensions пакета NuGet.
В предыдущем коде элемент AddMyLibraryService:
- Расширяет экземпляр IServiceCollection
-
IConfiguration Определяет параметр
namedConfigurationSection - Вызывает Configure<TOptions>(IServiceCollection, IConfiguration), передавая параметр
LibraryOptionsуниверсального типа и экземплярnamedConfigurationSectionдля настройки
Потребители в этом шаблоне предоставляют ограниченный экземпляр именованного IConfiguration раздела:
using ExampleLibrary.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMyLibraryService(
builder.Configuration.GetSection("LibraryOptions"));
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();
Вызов .AddMyLibraryService осуществляется на типе IServiceCollection.
Как автор библиотеки, вы сами определяете значения по умолчанию.
Замечание
Можно привязать конфигурацию к экземпляру параметров. Однако существует риск конфликтов имен , что приведет к ошибкам. Кроме того, при привязке вручную таким образом можно ограничить потребление шаблона параметров, делая его доступным для однократного чтения. Изменения параметров не будут перераспределены, поэтому пользователи не смогут использовать интерфейс IOptionsMonitor.
services.AddOptions<LibraryOptions>()
.Configure<IConfiguration>(
(options, configuration) =>
configuration.GetSection("LibraryOptions").Bind(options));
Вместо этого следует использовать BindConfiguration метод расширения. Этот метод расширения привязывает конфигурацию к экземпляру параметров, а также регистрирует источник маркера изменений для раздела конфигурации. Это позволяет потребителям использовать интерфейс IOptionsMonitor .
Параметр пути раздела конфигурации
Потребители вашей библиотеки могут захотеть указать путь к разделу конфигурации для привязки вашего основного типа TOptions. В этом сценарии вы определяете string параметр в методе расширения.
using Microsoft.Extensions.DependencyInjection;
namespace ExampleLibrary.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyLibraryService(
this IServiceCollection services,
string configSectionPath)
{
services.AddOptions<SupportOptions>()
.BindConfiguration(configSectionPath)
.ValidateDataAnnotations()
.ValidateOnStart();
// Register lib services here...
// services.AddScoped<ILibraryService, DefaultLibraryService>();
return services;
}
}
В предыдущем коде элемент AddMyLibraryService:
- Расширяет экземпляр IServiceCollection
-
stringОпределяет параметрconfigSectionPath - Звонки:
-
AddOptions с типовым параметром
SupportOptions -
BindConfiguration с заданным
configSectionPathпараметром - ValidateDataAnnotations для проверки аннотации данных
- ValidateOnStart принудительное применение проверки при запуске, а не во время выполнения
-
AddOptions с типовым параметром
В следующем примере пакет NuGet Microsoft.Extensions.Options.DataAnnotations используется для включения проверки заметки данных. Класс SupportOptions определяется следующим образом:
using System.ComponentModel.DataAnnotations;
public sealed class SupportOptions
{
[Url]
public string? Url { get; set; }
[Required, EmailAddress]
public required string Email { get; set; }
[Required, DataType(DataType.PhoneNumber)]
public required string PhoneNumber { get; set; }
}
Представьте, что используется следующий файл JSON appsettings.json :
{
"Support": {
"Url": "https://support.example.com",
"Email": "help@support.example.com",
"PhoneNumber": "+1(888)-SUPPORT"
}
}
Action<TOptions> параметр
Пользователи вашей библиотеки могут быть заинтересованы в использовании лямбда-выражения, которое возвращает экземпляр вашего класса параметров. В этом сценарии вы определяете Action<LibraryOptions> параметр в методе расширения.
using Microsoft.Extensions.DependencyInjection;
namespace ExampleLibrary.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyLibraryService(
this IServiceCollection services,
Action<LibraryOptions> configureOptions)
{
services.Configure(configureOptions);
// Register lib services here...
// services.AddScoped<ILibraryService, DefaultLibraryService>();
return services;
}
}
В предыдущем коде элемент AddMyLibraryService:
- Расширяет экземпляр IServiceCollection
- Определяет Action<T> параметр
configureOptions, гдеTнаходитсяLibraryOptions - ВызовыConfigure, заданные действием
configureOptions
Потребители в этом шаблоне предоставляют лямбда-выражение (или делегат, удовлетворяющий параметру Action<LibraryOptions> ):
using ExampleLibrary.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMyLibraryService(options =>
{
// User defined option values
// options.SomePropertyValue = ...
});
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();
Параметр экземпляра параметров настроек
Потребители библиотеки могут предпочесть предоставить экземпляр встроенных параметров. В этом сценарии вы предоставляете метод расширения, который принимает экземпляр объекта options, LibraryOptions.
using Microsoft.Extensions.DependencyInjection;
namespace ExampleLibrary.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyLibraryService(
this IServiceCollection services,
LibraryOptions userOptions)
{
services.AddOptions<LibraryOptions>()
.Configure(options =>
{
// Overwrite default option values
// with the user provided options.
// options.SomeValue = userOptions.SomeValue;
});
// Register lib services here...
// services.AddScoped<ILibraryService, DefaultLibraryService>();
return services;
}
}
В предыдущем коде элемент AddMyLibraryService:
- Расширяет экземпляр IServiceCollection
- Вызовы OptionsServiceCollectionExtensions.AddOptions<TOptions>(IServiceCollection) с параметром типа
LibraryOptions - Цепочка вызова Configure, в который указываются значения параметров по умолчанию, которые можно переопределить из заданного
userOptionsэкземпляра.
Потребители в этом паттерне предоставляют экземпляр LibraryOptions класса, определяя значения требуемых свойств на месте:
using ExampleLibrary.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMyLibraryService(new LibraryOptions
{
// Specify option values
// SomePropertyValue = ...
});
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();
После настройки
После того как все значения параметров конфигурации привязаны или указаны, функция после настройки доступна. При использовании того же Action<TOptions> параметра, подробно описанного ранее, вы можете выбрать вызов PostConfigure. "Постконфигурация выполняется после всех вызовов .Configure." Существует несколько причин, по которым вы хотите рассмотреть возможность использования PostConfigure:
-
Порядок выполнения. Вы можете переопределить любые значения конфигурации, заданные в вызовах
.Configure. - Проверка. Вы можете проверить значения по умолчанию после применения всех остальных конфигураций.
using Microsoft.Extensions.DependencyInjection;
namespace ExampleLibrary.Extensions.DependencyInjection;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyLibraryService(
this IServiceCollection services,
Action<LibraryOptions> configureOptions)
{
services.PostConfigure(configureOptions);
// Register lib services here...
// services.AddScoped<ILibraryService, DefaultLibraryService>();
return services;
}
}
В предыдущем коде элемент AddMyLibraryService:
- Расширяет экземпляр IServiceCollection
- Определяет Action<T> параметр
configureOptions, гдеTнаходитсяLibraryOptions - ВызовыPostConfigure, заданные действием
configureOptions
Потребители в этом шаблоне предоставляют лямбда-выражение (или делегат, удовлетворяющий Action<LibraryOptions> параметру), так же, как и Action<TOptions> параметр в сценарии, отличном от последующей конфигурации:
using ExampleLibrary.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddMyLibraryService(options =>
{
// Specify option values
// options.SomePropertyValue = ...
});
using IHost host = builder.Build();
// Application code should start here.
await host.RunAsync();