如何根据部署环境在静态 class 中加载 appsettings.json,以便我可以在其他 class 库中使用

How to load appsettings.json inside a Static class based on deploy environment so that I can use in other class libraries

我正在处理一个迁移项目。我需要在其他 class 库中使用我的应用程序设置。所以在谷歌搜索和 Whosebuging 之后,我将我的 appsettings.json 加载到静态 class 中,如下所示:

public static class ReadAppConfig
    {
        private static readonly IConfiguration Root;
        private static readonly ConfigurationBuilder ConfigurationBuilder;

        static ReadAppConfig()
        {
            if (ConfigurationBuilder == null)
            {
                ConfigurationBuilder = new ConfigurationBuilder();
                ConfigurationBuilder.SetBasePath(Directory.GetCurrentDirectory());
                ConfigurationBuilder.AddJsonFile("appsettings.json", optional: true);
                ConfigurationBuilder.AddJsonFile("appsettings.QA.json", optional: true);
                ConfigurationBuilder.AddJsonFile("appsettings.Dev.json", optional: true);
                ConfigurationBuilder.AddJsonFile("appsettings.Staging.json", optional: true);

                if (Root == null)
                    Root = ConfigurationBuilder.Build();

            }
        }

        public static string UserManualFile => Root.GetSection("AppSettings:SomeKey").Value;
    }

所以现在我可以在其他库中像 ReadAppConfig.UserManualFile 一样获得 UserManualFile

这很好用。但它总是只从 appsettings.Staging.json 读取。如何根据部署环境进行阅读。

我无法在此处获取 IHostingEnvironment,因为这是静态的 class。

请协助/建议我以正确的方式做到这一点。

谢谢

这里有两个问题。首先,不要使用静态 class。配置被设计为依赖注入,而依赖注入从根本上与静态不兼容。事实上,静态几乎总是错误的方法,依赖注入与否。其次,图书馆应该只依赖于抽象,而不是具体 data/implementations.

老实说,存在三个问题,最后一个是这里的杀手:您的用例需要 IHostingEnvironment,并且绝对知道如何在静态 class 中获得它。游戏结束。

您可以通过多种方式前往此处,但我会坚持我认为最好的选择。最终,您的图书馆似乎只需要 UserManualFile。因此,它们应该依赖于 all:大概是与用户手册的位置相对应的字符串。所以,你会做这样的事情:

public class SomeLibraryClass
{
    private readonly string _userManualFie;

    public SomeLibraryClass(string userManualFile)
    {
        _userManualFile = userManualFile;
    }
}

这需要最少的知识,并为您的库提供最多的抽象。它不再关心它在哪里或如何获取文件位置,只关心它获取它。

然后,在您的实际应用中,您将使用强类型配置来提供此值:

services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

...

services.AddScoped(p =>
{
    var appSettings = p.GetRequiredService<IOptions<AppSettings>>();
    return new SomeLibraryClass(appSettings.Value.UserManualFile);
});

完成。现在,如果图书馆确实需要其他东西,您可以选择将自定义 "settings" class 传递给图书馆。这个 class 应该来自图书馆,以便它记录它需要的东西。例如,在您的图书馆中,您可以创建一个 class,例如:

public class SomeLibrarySettings
{
    public string Foo { get; set; }
    public string Bar { get; set; }
    // etc.
}

然后,您的图书馆 class(es) 将注入:

public SomeLibraryClass(SomeLibrarySettings settings)

最后,在您的应用中,您可以手动编写此设置 class 实例或将其注入。注入它仍然需要您手动组合它,因此只有在您要在多个 classes 之间共享它时才有意义。

手动撰写

services.AddScoped(p =>
{
    var appSettings = p.GetRequiredService<IOptions<AppSettings>>();
    var someLibrarySettings = new SomeLibrarySettings
    {
        Foo = appSettings.Value.Foo,
        Bar = appSettings.Value.Bar,
        // etc.
    };
    return SomeLibraryClass(someLibrarySettings);
});

注入

services.AddSingleton(p =>
{
    var appSettings = p.GetRequiredService<IOptions<AppSettings>>();
    return new SomeLibrarySettings
    {
        Foo = appSettings.Value.Foo,
        Bar = appSettings.Value.Bar,
        // etc.
    };
});

services.AddScoped<SomeLibraryClass1>();
services.AddScoped<SomeLibraryClass2>();
// etc.

因为SomeLibrarySettings注册在服务集合中,所以会自动注入到依赖它的库classes中。

最后,值得注意的是,因为您正在将配置逻辑移动到它实际所属的位置,所以您甚至不再需要担心环境问题。 ASP.NET 核心已经设置为加载适当的环境设置,因此它可以正常工作。