ASP.NET核心访问静态类的配置

bir*_*dus 47 asp.net-core-mvc

我想要一个访问Configuration对象的简单静态类.所有配置信息都已从Startup类中的appsettings.json文件中读取.我只需要一种简单的方法来访问它.这可能吗?

namespace MyNamespace
{
    public static class Config
    {
        public string Username => Configuration["Username"];
        public string Password => Configuration["Password"];
    }
}
Run Code Online (Sandbox Code Playgroud)

应用中的其他任何地方:

string username = Config.Username;
string password = Config.Password;
Run Code Online (Sandbox Code Playgroud)

小智 52

  1. 在服务层创建ConfigurationHelper静态类,这样就可以在其他层使用它而无需循环依赖。
public static class ConfigurationHelper
    {
        public static IConfiguration config;
        public static void Initialize(IConfiguration Configuration)
        {
            config = Configuration;
        }
    }
Run Code Online (Sandbox Code Playgroud)
  1. 在Startup类的ConfigureServices方法中初始化ConfigurationHelper。
ConfigurationHelper.Initialize(Configuration);
Run Code Online (Sandbox Code Playgroud)
  1. 在任何你想要的地方使用它,包括你的静态类
e.g: ConfigurationHelper.config.GetSection("AWS:Accesskey").Value;
Run Code Online (Sandbox Code Playgroud)

  • 你节省了我的时间 .net 6 在program.cs ConfigurationHelper.Initialize(builder.Configuration); (8认同)
  • 这是 ASP.NET Core 3.1+ 的完美解决方案。我在 .NET 5 上测试了它并且运行得很好。感谢分享@pedram (2认同)

小智 21

基于与上述相同的原理略短的版本...

public Startup(IConfiguration configuration)
{
    Configuration = configuration;
    StaticConfig = configuration;
}

public static IConfiguration StaticConfig { get; private set; }
Run Code Online (Sandbox Code Playgroud)

要在另一个静态类中使用:

string connString = Startup.StaticConfig.GetConnectionString("DefaultConnection");
Run Code Online (Sandbox Code Playgroud)

  • 在不同的类库之间共享这个配置值会很棘手。想象一下,您有多个项目之间的基础设施横切共享配置/设置? (4认同)
  • 我很困惑为什么这不是公认的答案。这有什么风险吗?看起来简单而实用。 (2认同)
  • 因为这是一种反模式。您应该能够注入事物需要的所有事物,以便可以在测试期间替换它们。当它是带有“私有设置程序”的静态属性时,您将如何替换它?您必须将其设为“公开”只是为了进行测试,这是不对的。 (2认同)
  • 我不认为这是一种反模式,因为 IConfiguration 有绑定方法,允许您出于这个原因将其绑定到类。但我不会将其存储为 IConfiguration。反复将字符串解析为布尔值和整数等实际类型是我在微服务世界中更关心的反模式。当您更改测试值时,不必设置“StaticConfig”。您可以在测试设置中轻松设置“MyConfigObject.MyProperty = 5”并继续前进。 (2认同)

Tấn*_*ang 16

我也有类似的问题,在阅读了微软的文档后。我已经解决了:

  1. 创建静态 ApplicationSettings 类
public static class ApplicationSettings
{
    public const string User = "UserOptions";

    public static UserOptions UserOptions { get; set; } = new UserOptions();

    // other options here...
}
Run Code Online (Sandbox Code Playgroud)
  1. 创建选项类
public class UserOptions
{
    public string Username { get; set; };

    public string Password { get; set; };
}
Run Code Online (Sandbox Code Playgroud)
  1. 初始化 Program.cs 中的 Options 类
ConfigurationManager configuration = builder.Configuration;

configuration.GetSection(ApplicationSettings.User).Bind(ApplicationSettings.UserOptions);
Run Code Online (Sandbox Code Playgroud)
  1. 更新您的 appsettings.json
{
  "UserOptions": {
    "Username": "input_your_username_here",
    "Password": "input_your_password_here"
  }
}
Run Code Online (Sandbox Code Playgroud)
  1. 您现在可以在项目中的任何位置调用它
public void MethodA() 
{
    string username = ApplicationSettings.UserOptions.Username;
    string password = ApplicationSettings.UserOptions.Password;
}

public static void MethodB() 
{
    string username = ApplicationSettings.UserOptions.Username;
    string password = ApplicationSettings.UserOptions.Password;
}
Run Code Online (Sandbox Code Playgroud)

希望这可以很好地帮助你。


Soe*_*hay 14

经过大量研究,这适用于(在 ASPNetCore 2.2 中)从静态类访问 appsettings.json 配置,但由于某种原因 appsettings.development.json 不再正确加载,但它可能是我项目中的其他东西把它搞砸了。reloadOnChange 确实有效。作为奖励,它还具有 IHostingEnvironment 和 IHttpContextAccessor。虽然这有效,但我最近决定切换回更多 DI 方法以遵循其他人提到的范式转变。

因此,这是在静态类中访问某些 DI 内容(包括配置)的众多方法之一:

AppServicesHelper.cs:

public static class AppServicesHelper
{
        static IServiceProvider services = null;

        /// <summary>
        /// Provides static access to the framework's services provider
        /// </summary>
        public static IServiceProvider Services
        {
            get { return services; }
            set
            {
                if (services != null)
                {
                    throw new Exception("Can't set once a value has already been set.");
                }
                services = value;
            }
        }

        /// <summary>
        /// Provides static access to the current HttpContext
        /// </summary>
        public static HttpContext HttpContext_Current
        {
            get
            {
                IHttpContextAccessor httpContextAccessor = services.GetService(typeof(IHttpContextAccessor)) as IHttpContextAccessor;
                return httpContextAccessor?.HttpContext;
            }
        }

        public static IHostingEnvironment HostingEnvironment
        {
            get
            {
                return services.GetService(typeof(IHostingEnvironment)) as IHostingEnvironment;
            }
        }

        /// <summary>
        /// Configuration settings from appsetting.json.
        /// </summary>
        public static MyAppSettings Config
        {
            get
            {
                //This works to get file changes.
                var s = services.GetService(typeof(IOptionsMonitor<MyAppSettings>)) as IOptionsMonitor<MyAppSettings>;
                MyAppSettings config = s.CurrentValue;

                return config;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

启动.cs:

public Startup(IHostingEnvironment env)
{
            var builder = new ConfigurationBuilder()
                .SetBasePath(env.ContentRootPath)
                .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
                .AddEnvironmentVariables();
            Configuration = builder.Build();
 }

 public void ConfigureServices(IServiceCollection services)
 {
//...

        services.AddHttpContextAccessor();//For HttpContext.

        // Register the IOptions object
        services.Configure<MyAppSettings>(Configuration.GetSection(nameof(MyAppSettings)));

        //Explicitly register the settings object by delegating to the IOptions object so that it can be accessed globally via AppServicesHelper.
        services.AddSingleton(resolver => resolver.GetRequiredService<IOptionsMonitor<MyAppSettings>>().CurrentValue);
 }

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...
   AppServicesHelper.Services = app.ApplicationServices;
//...
}
Run Code Online (Sandbox Code Playgroud)

控制器:

public class MyController: Controller
{
   public MyController()
   {
   }

   public MyAppSettings Config => AppServicesHelper.Config;

   public async Task<IActionResult> doSomething()
   {
            testModel tm = await myService.GetModel(Config.Setting_1);
            return View(tm);
   }
}
Run Code Online (Sandbox Code Playgroud)

另一个类库:

public static class MyLibraryClass
{
     public static string GetMySetting_ => AppServicesHelper.Config.Setting_1; 
     public static bool IsDev => AppServicesHelper.HostingEnvironment.IsDevelopment();
}
Run Code Online (Sandbox Code Playgroud)

MyAppSettings.cs 是映射到 appsettings.json 中 MyAppSettings 部分的任何类:

public class MyAppSettings
{
    public string Setting_1 {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "MyAppSettings": {
      "Setting_1": "something"
   }
 }
Run Code Online (Sandbox Code Playgroud)


小智 8

我同意mcbowes,它在文档中,但第一个例子看起来更像你需要的...想要:

public class Program
{
    public static IConfigurationRoot Configuration { get; set; }
    public static void Main(string[] args = null)
    {
        var builder = new ConfigurationBuilder()
             .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json");

        Configuration = builder.Build();

        Console.WriteLine($"option1 = {Configuration["option1"]}");

        // Edit:
        IServiceCollection services = new ServiceCollection();
        services.AddOptions();
        services.Configure<HelloWorldOptions>(_configuration.GetSection("HelloWorld"));
        // And so on...
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @Tubbe你能提供一个如何运作的例子吗?从我在那篇文章中读到的内容中,您仍然需要在构造函数中提供选项,这在静态类中是不可能的. (4认同)
  • 是的,但是如何从另一个内部静态类访问此Configuration实例,而不必每次都重新构建它? (3认同)

小智 7

尽量避免使用静态类并使用 DI

namespace MyNamespace {

  public interface IConfig {
    string Username { get; }
    string Password { get; }
  }


  public class Config : IConfig {
    public Config(IConfiguration configuration) {
      _configuration = configuration;
    }
    readonly IConfiguration _configuration;
    public string Username => _configuration["Username"];
    public string Password => _configuration["Password"];
  }


}
Run Code Online (Sandbox Code Playgroud)

StartUp 类中的设置 DI

public class Startup {
  public void ConfigureServices(IServiceCollection services) {
    //...
    services.AddTransient<IConfig, Config>(); 
    ...
  }
}
Run Code Online (Sandbox Code Playgroud)

并像这样使用它

  public class TestUsage {
    public TestUsage(IConfig config) {
      _config = config;
    }
    readonly IConfig _config;
    public string Username => _config.Username;
    public string Password => _config.Password;
  }
Run Code Online (Sandbox Code Playgroud)

  • 为什么拥有一个静态类如此糟糕?我知道字典访问速度很快,但是不得不使用 `if(configuration["enabled"] == "True")` 或 `if(configuration.GetValue&lt;int&gt;("enabled")) ` 当我觉得 `if(MyStaticClass.Enabled)` 对于每秒调用多次的方法来说更快更轻。 (5认同)
  • 如果要将 NET Framework 迁移到 NET Core,则必须修改所有使用应用程序设置的类,以便注入配置值(IOptions、IConfiguration 或其他)。如果你有一个庞大的项目,编辑类将需要大量的时间和测试。:-O 希望看到一种没有 DI 和修改类构造函数的更简单的方法 (4认同)

Ahm*_*aff 6

您可以使用Signleton模式从任何地方访问您的配置

    public class ConnectionStrings
    {
        private ConnectionStrings()
        {
        }
        // property with getter only will not work.
        public static ConnectionStrings Instance { get; protected set; } = new ConnectionStrings();

        public string DatabaseConnection { get; set; }
    }
Run Code Online (Sandbox Code Playgroud)

在你的创业班

    public class Startup
    {
        private readonly IConfiguration configuration;

        public Startup(IConfiguration configuration)
        {
            this.configuration = configuration;
            configuration.GetSection("ConnectionStrings").Bind(ConnectionStrings.Instance);
        }

        public void ConfigureServices(IServiceCollection services)
        {
        }

        public void Configure(IApplicationBuilder app)
        {
        }
    }
Run Code Online (Sandbox Code Playgroud)


chr*_*989 5

这已经说过了,但我还是要说一下。

我相信.Net Core 希望开发者通过依赖注入获得价值。这是我从研究中注意到的,但我也做了一些推测。作为开发人员,我们需要遵循这种范式转变才能很好地使用 .Net Core。

选项模式是静态配置的一个很好的替代方案。在你的情况下,它看起来像这样:

应用程序设置.json

{
  "Username": "MyUsername",
  "Password": "Password1234"
}
Run Code Online (Sandbox Code Playgroud)

系统用户.cs

{
  "Username": "MyUsername",
  "Password": "Password1234"
}
Run Code Online (Sandbox Code Playgroud)

启动.cs

public class SystemUser 
{
  public string Username { get; set; } = "";
  public string Password { get; set; } = "";
}
Run Code Online (Sandbox Code Playgroud)

要使用 SystemUser 类,我们执行以下操作。

测试控制器.cs

services.Configure<SystemUser>(Configuration);
Run Code Online (Sandbox Code Playgroud)

尽管我们没有使用静态类,但我认为这是满足您需求的最佳选择。否则,您可能必须在 Startup 类中使用静态属性,在我看来这是一个可怕的解决方案。


mcb*_*wes -3

考虑使用此处的ASP.NET Core 配置说明。

您可以创建一个类来存储您的配置设置,然后访问这些值,如下所示:

_config.UserName
Run Code Online (Sandbox Code Playgroud)

在启动-配置服务中:

services.Configure<Config>(Configuration.GetSections("General"));
Run Code Online (Sandbox Code Playgroud)

然后只需在需要的地方注入您的对象即可:

IOptions<Config> config
Run Code Online (Sandbox Code Playgroud)

  • 这个问题具体是关于在“静态类”中使用它的 (3认同)
  • @SerjSagan 尽管问题专门询问静态类,但他们可能不理解从 .NET 到 .NET Core 的范式转变。因此,静态类不是最佳答案,因此选项模式应该是有效的答案。 (2认同)