Могу ли я внести необходимые изменения в ASP.NET Ядро?

#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