【问题标题】:Access to configuration without dependency injection无需依赖注入即可访问配置
【发布时间】:2017-01-20 20:38:58
【问题描述】:

我想知道是否有一种方法可以在不使用依赖注入的情况下访问配置 (Microsoft.Extensions.Configuration)。我看到的唯一示例是通过构造函数注入(使用 IOptions 或直接注入 Configuration)。

我的困境是我有一个实用程序类——而不是一个服务——它有静态方法来动态地做事。在其中一些静态方法中,我想从 appsettings.json 动态检索几个属性。由于这严格来说是一个实用程序类,我不想将这个类注入到需要使用实用程序中的一两个方法的每个其他类中。

关于如何在没有某种依赖注入的情况下访问 appsettings.json 属性的任何想法。

仅供参考:使用 c# 和 .net core 1.1

【问题讨论】:

  • @DanielGatti 答案使用注入。不是我要找的。再次是我的实用程序类。它不是服务,没有接口,不应该被注入。你要做的就是使用它:UtilityClass.DoSomething();
  • 方法需要是静态的吗?每个需要使用 Utility 的类是否可以只拥有一个 Utility 类型的私有成员,该成员在构造类对象时设置/创建?
  • @BackDoorNoBaby 那么您是否建议注入该实用程序?不过,要回答您的问题,第 1 次不(尽管首选)取决于第 2 次。
  • 我之前没有去寻找这个特定的配置文件,如果我误解了上下文,请原谅我。我假设问题是您想要存储对检索到的配置的引用,而不是每次都通过 ConfigurationBuilder 运行它?你可以将你的静态工具换成单例模式,这样你就可以做到这一点(注意线程安全)。也就是说,对我来说,我想我会尝试以某种方式注入它以消除依赖关系。

标签: c# .net-core


【解决方案1】:

哇,这么多的 cmets,为什么人们不回答这个问题,而不是告诉别人他们不想做他们明显做的事情。无论如何,希望这会让两个阵营都满意。

如果您采用具有单个公共构造函数的标准 AppSettings 类,该构造函数采用可用于填充所有 AppSettings 属性的 IConfiguration,这将保留依赖注入的能力。

如果在构造函数的最后我们设置了一个指向当前 AppSettings 实例的静态属性“Current”,这将允许我们从该点通过静态属性访问设置,而无需进一步注入。

如果我们现在创建一个静态 Default 'GetCurrentSettings' 方法来从 json 文件中获取设置,这可以用作默认实例化,因此如果调用 'Current' 并将其设置为 null,我们就可以离开并从文件中填充设置。这是我的意思的一个例子......

public class AppSettings
{
    private static AppSettings _appSettings;

    public string AppConnection { get; set; }

    public AppSettings(IConfiguration config)
    {
        this.AppConnection = config.GetValue<string>("AppConnection");

        // Now set Current
        _appSettings = this;
    }

    public static AppSettings Current
    {
        get
        {
            if(_appSettings == null)
            {
                _appSettings = GetCurrentSettings();
            }

            return _appSettings;
        }
    }

    public static AppSettings GetCurrentSettings()
    {
        var builder = new ConfigurationBuilder()
                        .SetBasePath(Directory.GetCurrentDirectory())
                        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                        .AddEnvironmentVariables();

        IConfigurationRoot configuration = builder.Build();

        var settings = new AppSettings(configuration.GetSection("AppSettings"));

        return settings;
    }
}

因此,您可以在代码 AppSettings.Current.AppConnection 中的任何位置调用

如果它是使用 DI 实例化的,则将检索注入的版本,否则将从 appsettings.json 文件中获取默认版本。我怀疑它是否让每个人都满意,我不确定我是否已经很好地解释了它,但希望它是有道理的。

【讨论】:

  • 加 1 表示“人们为什么不直接回答问题”。我厌倦了被告知我不应该做我要求做的事情。
  • +1 的原因与@ProfK 所说的相同。我确信他们正在努力帮助您改进代码风格,但我确实感受到了您的痛苦。每个人都认为你很愚蠢,需要被告知你想问什么,这有点侮辱人。 (在某些情况下,它实际上是,但它的侮辱性永远不会少。)他们应该说明你的问题的答案,然后提供替代方案。或者至少解释一下他们没有回答您的问题并询问您是否希望看到另一种方法。另一方面,SO 是免费的,所以无论如何你得到的比付出的多,呵呵。
  • 我只是想补充一点,对于较新版本的 .NET Core,您需要包含以下包:Microsoft.Extensions.Configuration;Microsoft.Extensions.Configuration.Json;Microsoft.Extensions.Configuration.EnvironmentalVariables;Microsoft.Extensions.Configuration.FileExtensions;
  • 要获取@Propagating 评论的更多详细信息,并修复此代码中的错误,thisthis SO 问题真的很有帮助。
  • 很好的答案,其中一种有用的情况是在集成测试中不能选择依赖注入。
【解决方案2】:

我刚刚在Startup静态中做了config属性:

public static IConfiguration Configuration { get; set; }

现在我可以在应用程序的任何位置使用Startup.Configuration 访问它。

【讨论】:

  • 这个问题是 Startup 现在暴露了,并且依赖于所有需要“静态”配置的人。 IMO 这并不理想,因为这是 Startup 类 - 不是预期目的。最近使用自定义 AppSettings 类的答案更合适,因为它在某种程度上模仿了专门为提供配置而构建的核心前时代的 ConfigurationManager.AppSettings。但是,是的,如果您可以从代码中需要它的任何位置调用 Startup.Configuration,您的解决方案就会起作用。
  • @LosMorales 是的,但在上面使用AppSettings 的答案中,配置被注入其中。如果我要在那里注入配置,我不妨在需要的地方注入它,这就是我提出这个问题的全部原因。例如。我使用var model = new ProductViewModel 并且在该视图模型中需要一个IConfiguration,我不能使用注入参数。
【解决方案3】:

我完全同意@Hoot 建议的解决方案,但我对课程的修改很少。我修改了类,因为我需要传递动态键来获取相同的值..

配置类:

public class ConfigHelper
    {

        private static ConfigHelper _appSettings;

        public string appSettingValue { get; set; }

        public static string AppSetting(string Key)
        {
          _appSettings = GetCurrentSettings(Key);
          return _appSettings.appSettingValue;
        }

        public ConfigHelper(IConfiguration config, string Key)
        {
            this.appSettingValue = config.GetValue<string>(Key);
        }

        public static ConfigHelper GetCurrentSettings(string Key)
        {
            var builder = new ConfigurationBuilder()
                            .SetBasePath(Directory.GetCurrentDirectory())
                            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                            .AddEnvironmentVariables();

            IConfigurationRoot configuration = builder.Build();

            var settings = new ConfigHelper(configuration.GetSection("AppSettings"), Key);

            return settings;
        }
    }

Appsettings.Json 配置:

 "AppSettings": {
    "WebApplicationUrl": "http://localhost:0000/",
    "ServiceUrl": "http://localhost:0000/",
    "CommonServiceUrl": "http://localhost:0000/"
  }

调用示例:

string ServiceUrl = ConfigHelper.AppSetting("ServiceUrl");

所以从现在开始我们可以传递动态密钥了。

【讨论】:

  • 这缺少强类型属性提供的自动完成功能。一个更好的选择是复制这个 public string AppConnection { get; set; } 代码行 @Hoots 回答您在 appsettings.json 中的其他配置值,例如 WebApplicationUrlServiceUrl i> 等
【解决方案4】:

我已将@Ankit Mori 的答案修改为更好的动态解决方案,并且还具有强类型属性。

using System.IO;
using Microsoft.Extensions.Configuration;

public class AppSettings
{

    #region Methods

    public static string GetSettingValue(string MainKey, string SubKey)
    {
        return Configuration.GetSection(MainKey).GetValue<string>(SubKey);
    }

    #endregion

    #region Properties

    public static IConfigurationRoot _configuration;
    public static IConfigurationRoot Configuration
    {
        get
        {
            if (_configuration == null)
            {
                IConfigurationBuilder builder = new ConfigurationBuilder()
                        .SetBasePath(Directory.GetCurrentDirectory())
                        .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
                        .AddEnvironmentVariables();
                _configuration = builder.Build();
            }
            return _configuration;
        }
    }
    public static string MainAPI
    {
        get
        {
            return Configuration.GetSection("AppSettings").GetValue<string>("AppConnection");
        }
    }

    #endregion

}

【讨论】:

  • Intrsting 方法我正在尝试使用 sql EF Config 存储任何想法在不使用 json 文件时如何适应
  • 什么是 EF 配置存储?你是如何实现的?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-28
  • 1970-01-01
  • 2018-05-06
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
  • 2021-03-18
相关资源
最近更新 更多