【问题标题】:Simplified approach to IOptions<T>IOptions<T> 的简化方法
【发布时间】:2019-01-24 10:14:54
【问题描述】:

我试图在使用内置 DI 机制的同时获得与 ASP.NET Core 2.1 应用程序一致的 .NET Framework 类库。现在,我创建了一个配置类并将适当的部分添加到 appsettings.json:

services.Configure<MyConfig>(Configuration.GetSection("MyConfiguration"));
services.AddScoped<MyService>();

在类库中:

public class MyService 
{
    private readonly MyConfig _config;

    public MyService(IOptions<MyConfig> config)
    {
        _config = config.Value;
    }
}

但是,为了构建这个类库,我必须添加 Microsoft.Extensions.Options NuGet 包。问题是这个包携带了大量的依赖项,这些依赖项看起来相当多,只是为了一个接口而添加。

所以,最终的问题是,“我可以采取另一种方法来配置位于 .NET Framework 类库中的 DI 服务,它的依赖关系不重吗?

【问题讨论】:

  • 不丢失 MS 配置的作用域/可重新加载功能?不会。如果您对静态单例选项感到满意,您可以将选项类注册到 IoC 容器。但是当它改变时你不会得到新的配置并且它不会被限定(如果另一个请求修改它,它可以在中间请求中改变)
  • 依赖本身并不是什么坏事。它是 .NET Core 和 .NET Standard 的设计方式。在您拥有带有所有组件的大型胖框架之前。在 .NET Core/.NET Standard 中,它在包之间拆分,这就是您看到它的原因。 System.Memory 还包含重要的优化以减少内存分配和内存碎片,所以这是一件好事:P
  • 好吧,这种语气不会让你更进一步。就像我说的,如果您不关心范围选项保证和重新加载机制,您可以将MyConfig 注入您的服务而不是IOptions&lt;MyConfig&gt;,并在ConfigureServices 中进行额外注册:services.AddScope&lt;MyConfig&gt;(provider =&gt; provider.GetRequiredService&lt;IOptions&lt;MyConfig&gt;&gt;().Value);。但是 .NET Core 和 .NET Standard 现在已经相当成熟,独立于平台,可以在很多企业场景中使用(除非你需要基于 WCF 或 System.Web 的东西)
  • 我们确实使用 f/w,但 asp.net 已完全移至核心。所以别无选择,我们要么放弃网络,要么使用核心。没有更多来自 MS 的 TLC 用于 .NET :)。而且核心还不成熟,小版本之间有重大变化。它远非一个圆润的、精心设计的产品。我们希望这就是他们在明年推出 3.0 的原因,也许有人最终意识到这种混乱会适得其反,并决定稳定局势。我们现在拥有来自同一家公司的两种相互竞争的 .net 产品这一事实就已经足够令人不安了。由同一个人完成的事实是,嗯,有点精神分裂。
  • 我不得不问,因为我觉得这很有趣,哪些依赖是问题?

标签: asp.net-core dependency-injection asp.net-core-2.1 .net-4.7.1


【解决方案1】:

查看这篇由 Filip Wojcieszyn 撰写的文章。

https://www.strathweb.com/2016/09/strongly-typed-configuration-in-asp-net-core-without-ioptionst/

你添加扩展方法:

public static class ServiceCollectionExtensions
{
    public static TConfig ConfigurePOCO<TConfig>(this IServiceCollection services, IConfiguration configuration) where TConfig : class, new()
    {
        if (services == null) throw new ArgumentNullException(nameof(services));
        if (configuration == null) throw new ArgumentNullException(nameof(configuration));

        var config = new TConfig();
        configuration.Bind(config);
        services.AddSingleton(config);
        return config;
    }
}

在配置中应用它:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.ConfigurePOCO<MySettings>(Configuration.GetSection("MySettings"));
}

然后使用它:

public class DummyService
{
    public DummyService(MySettings settings)
    {
        //do stuff
    }
}

【讨论】:

  • 实际上,我通过在ConfigureServices 中应用Bind 解决了这个问题,但是我看到了在IServiceCollection 上扩展它的吸引力和清晰性,我实际上打算使用它来重构它方法,所以我也会接受你的回答。
  • 实际上不需要任何代码。 IServiceCollection 将处理配置部分的转换,正如我在下面的回答中概述的那样。传统上,服务的 null 检查是在消费者级别(即构造函数)完成的,所以我看不到这里添加的值。
【解决方案2】:

我不久前遇到了这个问题,如果你真的可以称之为问题的话。我想当我们看到这样的依赖列表时,我们都会感到有点震惊。但是正如@Tseng 所提到的,包含一堆额外的小程序集真的没什么大不了的(无论如何,由于另一个项目中的引用,它们将被包含在bin 中)。但我承认,仅仅为了选项界面就必须包含它们很烦人。

我的解决方法是解决 startup.cs 中的服务依赖关系并相应地调整服务的构造函数:

services.AddTransient<MyService>(Configuration.GetConfiguration("MyConfiguration"));

【讨论】:

  • 我遇到的问题与其说是被 shell 震惊了,不如说是这些库不仅仅是 asp.net 库,它们还被 WPF 项目共享,并且很多旧版 WinForms 共享它们。将这些依赖项放在业务类中对我们来说毫无意义,因为它们将成为其他项目的依赖项。
  • 我觉得你完全同意。我喜欢使用可以被认为是最低分母的依赖项来构建我的服务。因此,为什么我喜欢直接在 IOptions&lt;MyConfiguration&gt; 上注入 MyConfiguration
【解决方案3】:

如果您不关心IOptions 为您提供的任何东西,为什么不将IConfiguration 注入您的服务?

public class MyService
{
    private readonly IConfiguration _config;

    public MyService(IConfiguration config)
    {
        _config = config;
    }

    public void DoSomething()
    {
        var value = _config["SomeKey"];

        // doing something
    }
}

【讨论】:

  • 我会说注入IConfiguration比注入IOption&lt;T&gt;还要糟糕。它是配置值的 Service Locator 等效项,因为它完全隐藏了使用的配置值,而不是在构造函数中显式声明它们。它使类负责读取和转换这些值,而不是应用程序的启动路径。我什至将IConfiguration(任何位于组合根之外的任何类)的注入称为反模式。
  • 我同意这个评论。此外,IConfiguration 也是一个不需要的依赖项,它带有其他东西。
  • 除了注入IConfiguration 和你可以放入一个类的附加逻辑之外,问题在于配置键。如果结构简单,您可以使用var value = _config["SomeKey"];,但在更复杂的配置中,您最终可能会使用var value = _config["ParentKey:ChildKey:ChildKey"];
猜你喜欢
  • 2019-02-04
  • 2020-04-05
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-14
相关资源
最近更新 更多