【问题标题】:.NET Core 2, DI, configuration file.NET Core 2、DI、配置文件
【发布时间】:2019-02-14 22:48:37
【问题描述】:

我正在学习 .NET Core 2,但我不喜欢 DI 的管理方式……在网上我读到了类似以下步骤的内容:

  1. 创建类似 IService 的接口

  2. 为 IService 创建一个实现

  3. 将其添加到 .NET Core 容器的作用域中到解决依赖关系的 Startup.Configuration 方法中。

  4. 终于可以在我的自定义控制器的构造函数中使用它了。

在 .NET classic 中,我使用了专用的 XML 配置文件来管理依赖项:我可以使用配置文件(JSON 或 XML 相同)来做我在 Startup.Configuration 方法中必须做的事情吗?

...否则有人可以解释为什么将服务配置到 Startup.Configuration 是更好的方法吗?

非常感谢...

【问题讨论】:

  • 专用 XML 配置文件?你用的是什么图书馆?不过,没有什么能阻止你编写自己的版本,听起来很简单。
  • 如果感觉更好,你不能使用你正在使用的同一个库吗? .NET 本身并没有真正的 DI,Core 确实有一个默认实现,但你可以使用任何你想要的方式或库,只要它支持 Core
  • 我还没有找到适用于 .NET Core 的 WindsorCastle...但我的意思是:我无法想象 .NET Core 的默认 DI 容器不被认为与 appsettings.json 配置一起使用! !为什么我必须做类似代码的方法而不是 json 配置?我只是想了解...谢谢。
  • 我觉得你不喜欢用于 DI 的常规方法真的很奇怪。几乎所有其他人都对此感到满意,那么是什么让您如此烦恼?
  • 这是一个难题,往往会根据您的意见得到答案。通过 XML 配置依赖项总是很困难并且容易出错。当您重命名一个类或接口时,它不会重构您的 Xml 配置,并且在您尝试运行它刚刚发出的错误的应用程序之前,您没有任何错误... 基于代码的 DI 配置是类型安全的,并在 IDE 中为您提供编译错误当您重命名类(不重构重命名)或只是重构重命名时,它会在任何地方更新它。

标签: asp.net-core dependency-injection .net-core asp.net-core-mvc asp.net-core-webapi


【解决方案1】:

首先,要回答您的问题“我可以使用配置文件吗”,答案肯定是“是”。你为什么不应该稍后回答,但现在,这是一个穷人的版本,你可以通过添加到你的 appsettings.json 文件来做到这一点。请注意,此代码并非最佳代码,而是旨在向您展示如何可以实施此解决方案。

让我们从一些保存数据的类开始:

public class ServicesConfiguration
{
    public IEnumerable<ServiceItem> Singleton { get; set; }
    public IEnumerable<ServiceItem> Transient { get; set; }
}

public class ServiceItem
{
    public string Service { get; set; }
    public string Implementation { get; set; }
}

现在向您的 JSON 文件添加一个部分,您甚至可能希望将此文件保留在主配置之外,但这是我将留给您的实现细节:

{
    //snip main config....

    "Services" : {
        "Singleton": [
            { 
                "Service": "YourNamespace.IFoo1, YourNamespace", 
                "Implementation": "YourNamespace.Foo1, YourNamespace" 
            },   
            {
                "Service": "YourNamespace.IFoo2, YourNamespace", 
                "Implementation": "YourNamespace.Foo2, YourNamespace" 
            }  
        ],
        "Transient": [
            {
                "Service": "YourNamespace.IBar1, YourNamespace",
                "Implementation": "YourNamespace.Bar1, YourNamespace"
            }    
        ]
    }
}

现在还有一个扩展方法来配置它:

public static IServiceCollection AddFromConfigurationFile(this IServiceCollection services, 
    IConfigurationSection configuration)
{
    var servicesConfiguration = configuration.Get<ServicesConfiguration>();

    foreach(var service in servicesConfiguration.Singleton)
    {
        services.AddSingleton(Type.GetType(service.Service), Type.GetType(service.Implementation));
    }

    foreach(var service in servicesConfiguration.Transient)
    {
        services.AddTransient(Type.GetType(service.Service), Type.GetType(service.Implementation));
    }

    //Other scopes here...

    return services;
}

并像这样在ConifigureServices 中调用它:

services.AddFromConfigurationFile(Configuration.GetSection("Services"));

那么,很好很简单吧?为什么不应该这样做?我脑海中浮现出一些想法:

  1. 为什么要改变几乎所有 DI 实现的工作方式?如果它没有坏,为什么要修复它?仅仅因为您习惯了某种特定的方法,并不意味着它是一个好主意。
  2. 类型安全:您会丢失在配置文件中指定的类型的编译时检查。
  3. 安全性:在配置文件中包含它可以让某人将实现更改为他们自己选择的类。

我敢肯定还有更多,但是...这是你的应用程序!

【讨论】:

  • 好...我正在寻找这样的答案!非常感谢!
  • 如果我要使用 DI 来为不同的“客户”使用不同的实现,那么使用配置文件的一个“被批准”的理由会是什么?假设我有一个具有两种不同实现的“IFileOutput”,一种将文件写入磁盘,另一种将文件写入云(例如 Azure blob 存储)。我的应用程序被多个客户使用,每个客户都有自己的应用程序实例。使用基于文件的配置,我可以根据客户的需求轻松地将 IFileOutput 交换到我的任一实现。
  • @Björn 好吧,对于这种情况,我仍然希望使用不同的方法。我会允许一个文本文件来控制使用哪个实现,但不允许哪个实现在 DI 中注册。
  • @DavidG :好吧,我将使用这种技术正是因为我正在销售一种产品,其中一些模块是可选的。感谢您的示例,这正是我所需要的。
猜你喜欢
  • 2020-04-24
  • 1970-01-01
  • 2019-08-15
  • 2021-03-04
  • 2023-03-08
  • 2022-10-19
  • 2018-09-15
  • 2018-03-30
  • 2021-06-01
相关资源
最近更新 更多