#c# #asp.net-core #.net-core
Вопрос:
Вот мой стартовый код:
services.Configure<FooBarOptions>(Configuration.GetSection("FooBarOptions"));
Это было ошибкой, как я и хотел
services.Configure<FooBarOptions>(Configuration.GetSection("FooBar"));
Очевидно, что опечатка приводит к тому, что конфигурация не загружается. Есть ли способ вызвать ошибку при запуске, когда необходимый раздел конфигурации не существует?
Комментарии:
1. Я думаю, что просто проверьте
Configuration.GetSection("FooBar")
этоnull
илиempty
выбросьте исключение при запуске.2. Настройте обратный вызов после настройки и проверьте, действительно ли настроены параметры.
Ответ №1:
Используйте a PostConfigure<T>
с обратным вызовом, который будет выполняться после выполнения каждого Configure<T>
. Это позволит пользователю настроить параметр любым способом в любом порядке, а также позволит вам просмотреть (не)настроенные параметры и при необходимости создать исключение.
class FooBarOptions
{
public string AString { get; set; }
}
services.PostConfigure<FooBarOptions>(options => {
// ... validate configuration
if (options.AString == null)
{
throw new InvalidProgramException($"{nameof(FooBarOptions)} is not configured properly");
}
});
services.Configure<FooBarOptions>(Configuration.GetSection("FooBarOptions"));
Рекомендации
Ответ №2:
Если вы хотите, чтобы часть «привязки» вашего файла запуска была немного сжатой, будет работать метод расширения для любого IConfiguration
или IServiceCollection
. Вот базовая реализация.
static class ConfigurationBindingExtensions
{
public static void BindSection<T>(this IConfiguration configuration, IServiceCollection services, string sectionName) where T : class
{
var config = configuration.GetSection(sectionName);
if (config.Exists())
{
services.Configure<T>(config);
}
else
{
throw new ConfigurationSectionNotFoundException(sectionName);
}
}
}
[Serializable]
class ConfigurationSectionNotFoundException : Exception, System.Runtime.Serialization.ISerializable
{
public string SectionName { get; set; }
public ConfigurationSectionNotFoundException(string sectionName)
: this(sectionName, string.Format("Section {0} was not found in the configuration file", sectionName))
{
this.SectionName = sectionName;
}
public ConfigurationSectionNotFoundException(string sectionName, string message)
: base(message)
{
this.SectionName = sectionName;
}
protected ConfigurationSectionNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
: base(info, context)
{
if (info == null)
throw new ArgumentNullException(nameof(info));
SectionName = info.GetString("SectionName");
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, SerializationFormatter = true)]
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException(nameof(info));
info.AddValue("SectionName", SectionName);
base.GetObjectData(info, context);
}
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand, Flags = System.Security.Permissions.SecurityPermissionFlag.SerializationFormatter)]
void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
if (info == null)
throw new ArgumentNullException(nameof(info));
GetObjectData(info, context);
}
}
Тогда вы бы назвали это так:
Configuration.BindSection<FooBarOptions>(services, "FooBar");
Это вызовет пользовательское исключение, если раздел не определен — вы можете заменить его чем-то другим, если это имеет для вас больше смысла. Возможно, это перебор, но он поддерживает Startup.cs в хорошем и аккуратном состоянии.
Ответ №3:
попробуйте это
var exist = Configuration.GetSection("FooBar").Exist();
if (exist) services.Configure<FooBarOptions>(Configuration.GetSection("FooBar"));
else ....throw exception