【问题标题】:.NET Core 2.0 Modular Dependency Injection.NET Core 2.0 模块化依赖注入
【发布时间】:2018-02-12 16:12:06
【问题描述】:

我正在尝试构建一个包含核心和扩展包的库,例如 Entity Framework 及其数据库提供程序。

我想要做的是,当我使用依赖注入注册该库时,我想将具体实现作为参数提供。

想想英孚。为了在 EF 上使用 sql 提供程序,我们需要使用作为选项参数传递的 SQL 提供程序注册它,如下所示。

services.AddDbContext<ApplicationDbContext>(options =>
{
   options.UseSqlServer(Configuration["ConnectionString"]);
});

我想建立类似的结构。可以说我的框架将提供电影制片人。它将有用于框架相关类的producer.core 包和两个名为Producer.Extensions.HollywoodProducer.Extensions.Bollywood 的扩展包。

如果我想使用Hollywood提供者,我需要安装核心包和Hollywood扩展包。在注册时它应该看起来像

services.AddFilmProducer(options =>
{
   options.UseHollywoodProducer();
});

我什至找不到可以为我指明方向的关键字。我试图阅读实体框架的源代码,但对我来说太复杂了。

有大神指点一下吗?

提前致谢。

【问题讨论】:

  • 您必须在允许这样做的包中创建自己的扩展方法
  • 这就是我想要实现的目标,但没有任何运气。我无法使用自己的扩展方法构建该结构,这就是我要问的原因。有什么模式可以满足我的要求吗?这个有关键字吗?
  • 展示你是如何构建它的。你展示了你想要的样子,而不是你尝试过的样子
  • 其实我没有任何有意义的数据/代码可以和你分享。我被困。但我保证,如果我找到方法,我会分享。

标签: c# entity-framework dependency-injection .net-core


【解决方案1】:

我不确定我是否完全理解您的要求,但 .net 核心中的 DI 和扩展是一件容易的事。

假设您希望在 Startup.cs 中使用它

services.AddFilmProducer(options =>
{
   options.UseHollywoodProducer();
});

要实现这一点,请创建您的库并添加一个静态扩展类

public static class FilmProducerServiceExtensions
{
    public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<ProducerOptions> options)
    {
        // Create your delegate
        var producerOptions = new ProducerOptions();
        options(producerOptions);

        // Do additional service initialization
        return services;
    }
}

您的 ProducerOptions 实现可能的样子

public class ProducerOptions
{
    public void UseHollywoodProducer() 
    { 
        // Initialize hollywood
    }

    public void UseBollywoodProducer() 
    { 
        // Initialize bollywood
    }
}

如果您希望在服务中使用传递的 ProducerOptions,有两种方法可以做到。要么再次使用依赖注入,要么直接在扩展方法中使用服务提供者访问服务

var serviceProvider = services.BuildServiceProvider()
IYourService service = sp.GetService<IYourService>();

现在您可以使用原始的使用初始化部分了。

希望对你有帮助。

编辑:

澄清一下。要在服务中注入您的选项,您可以使用

services.Configure(ProducerOptions);

在您的扩展方法中,并通过

传递给您的服务构造函数
public YourService(IOptions<ProducerOptions>)

然后,您可以根据需要简化或复杂化您的选项。

此类扩展的有用链接可能是 .net 核心的 CORS 存储库:https://github.com/aspnet/CORS

在 cmets 之后编辑:

我想我现在明白了。您希望包扩展和实现特定选项,就像 serilog 对不同接收器所做的那样。小菜一碟。

废弃 ProducerOptions 实现。

假设您有一个带有初始空结构(BaseProducer 库)和接口的基础包

public interface IProducerOptions
{
    // base method signatures
}

您的服务扩展现在变为

public static class FilmProducerServiceExtensions
{
    public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<IProducerOptions> options)
    {
        // Do additional service initialization
        return services;
    }
}

现在您创建一个带有特定“好莱坞制片人”选项的新包,并且您想要扩展基本选项集

public static class HollyWoodExtensions
{
    public static void UseHollywoodProducer(this IProducerOptions options)
    {
        // Add implementation
    }
}

创建任意数量的包和 IProducerOptions 扩展,添加的方法将开始出现在您的 Startup.cs 中

services.AddFilmProducer(options =>
{
   options.UseHollywoodProducer();
});

【讨论】:

  • 这是一个很好的尝试。干得好。 UseHollywoodProducer 和其他代码也是选项类的扩展方法。其中选项类可以公开一个Use(PropducerType p),扩展方法将使用必要的值调用该Use(PropducerType p)
  • 感谢您的详细解释和示例代码。但我认为我们的 ProducerOptions 为好莱坞和宝莱坞的套餐创建了依赖项。我想我应该找到更抽象的方法来在核心包上生成选项,然后在实现包上编写实现类。如果我将 ProducerOptions 更改为接口或抽象类,这意味着我将无法在 AddFilmProducer 扩展方法上创建新的 ProducerOptions 实例。您认为还有其他方法可以将实现类与扩展包解耦吗?
猜你喜欢
  • 2018-03-03
  • 1970-01-01
  • 2020-11-24
  • 2016-05-22
  • 1970-01-01
  • 2021-04-17
  • 2020-11-20
  • 2021-10-23
  • 1970-01-01
相关资源
最近更新 更多