【问题标题】:ASP.NET Core 2.0 Dependency Injection default instanceASP.NET Core 2.0 依赖注入默认实例
【发布时间】:2018-03-23 13:29:09
【问题描述】:

我正在使用ASP.NET Core 2.0Microsoft.Extensions.DependencyInjection。我有几个类我不想指定它的实现或者我不需要指定。

例如:

public interface IMyService
{
    void WriteSomething();
}

public class MyService : IMyService
{
    private readonly MyObject myObject;

    public MyService(MyObject myObject)
    {
        this.myObject = myObject;
    }

    public void WriteSomething()
    {
        this.myObject.Write();
    }
}

public interface IOther
{
    string GetName();
}

public class Other : IOther
{
    public string GetName()
    {
        return "james bond";
    }
}

public class MyObject
{
    private readonly IOther other;

    public MyObject(IOther other)
    {
        this.other = other;
    }

    public void Write()
    {
        Console.WriteLine(string.Concat("hi ", this.other.GetName()));
    }
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        ...
        services.AddScoped<IOther, Other>();
        services.AddScoped<IMyService, MyService>();
        ...
    }
}

我只想指定IMyToolGeneralMyToolGeneralIOtherOther,但MyObject 不是,因为我有很多这样的类(验证器、助手......)和我不需要指定这些。

如何在ASP.NET Core 2.0 中做到这一点?

编辑

我需要ASP.NET Core 2.0 DI 可以注入 MyObject 的实例,而无需在 DI 配置中指定它。 MyObject 没有基类的契约(接口),其构造函数中的所有参数都在 DI 配置中指定。

编辑二 我重写了类并在 Unity 中包含了一个示例(有效)和 MS DI 中的相同示例(无效)

统一示例(工作)

class Program
{
    static void Main(string[] args)
    {
        var container = UnityConfig();

        var service = container.Resolve<IMyService>();

        service.WriteSomething();

        Console.ReadKey();
    }

    static UnityContainer UnityConfig()
    {
        var container = new UnityContainer();

        container.RegisterType<IMyService, MyService>();

        container.RegisterType<IOther, Other>();

        return container;
    }
}

MS DI(不工作) 未处理的异常:System.InvalidOperationException:尝试激活“ConsoleDI.MyService”时无法解析“ConsoleDI.MyObject”类型的服务。

class Program
{
    static void Main(string[] args)
    {
        var serviceProvider = new ServiceCollection()
                .AddTransient<IMyService, MyService>()
                .AddTransient<IOther, Other>()
                .BuildServiceProvider();

        var service = serviceProvider.GetService<IMyService>();

        service.WriteSomething();

        Console.ReadKey();
    }
}

【问题讨论】:

  • 也许services.AddTransient&lt;MyObject &gt;();
  • @Kirk Ready,我提供了更多细节
  • @IvanMilosavljevic 我需要避免这种情况。
  • @IvanMilosavljevic 是的,我知道,但我需要避免这种情况。在 Unity 中可以做到。
  • 您是否严格使用 Microsoft DI?有autofac property injection

标签: c# asp.net dependency-injection asp.net-core asp.net-core-2.0


【解决方案1】:

内置的依赖注入容器Microsoft.Extensions.DependencyInjection不支持基于约定的注册。因此,当您通常会设置一些约定时,例如命名空间中的所有类型都将注册为临时依赖项,这不适用于标准容器。

如果您仍想这样做,则必须将依赖注入容器更改为更强大的容器(请记住,内置容器设计是一个非常纤薄的容器),或创建您自己的基于约定的逻辑来注册您的依赖项。例如,您可以简单地遍历当前程序集并检查某个命名空间中的所有类型并注册它们:

var types = Assembly.GetExecutingAssembly()
    .GetTypes()
    .Where(t => t.Namespace == "Your.Custom.Namespace");

foreach (var type in types)
{
    services.AddTransient(type);
}

如果您不想注册所有类型,您还可以做一件事。 activator utilities 提供了一种方法来构造类型的对象,这些对象本身没有在容器中注册,但需要依赖来自要构造的容器。您可以使用ActivatorUtilities.CreateInstance 方法来创建对象。例如,使用您的服务定义,您可以像这样创建一个MyObject 实例:

var myObject = ActivatorUtilities.CreateInstance<MyObject>(serviceCollection);

这会自动从容器中获取IOther,并将其注入MyObject的构造函数中。 MyObject 不需要为此注册,但 IOther 需要。

所以这只适用于实例化未在容器中注册的类型。它不适用于其他类型所需的依赖项。依赖注入只能自动为那些在依赖注入容器中注册的依赖提供实例。

所以你不能通过依赖注入创建一个MyService对象,因为它的依赖,MyObject,没有注册。没有办法解决这个问题,如果您希望 DI 框架自动为您实例化对象,您必须注册它。

【讨论】:

  • 如果有人主动,创建这样的扩展可能更容易重复使用。如果 Microsoft 拒绝将这些添加到他们自己的库中的想法,那么没有什么能阻止任何人创建自己的 NuGet.org 包来为大众提供它们。
  • @NightOwl888 没有什么能阻止 you 这样做。如果您查看 NuGet,实际上有相当多的扩展包可用于框架的某些部分。 – 话虽如此,我个人并不喜欢基于约定的 DI 设置。如果您真的需要它们,那么您应该非常明确地表明这种情况正在发生。那几行并没有真正伤害并非常清楚地传达了意图。
【解决方案2】:

您可以通过

将它们添加到 DI
services.AddScoped<MyObject>();

或者更复杂的,比如

services.AddScoped(provider =>
{
    var res = new MyObject
    {
        Message = "Hello World 2"
    };
    return res;
});

您可以自己构造对象。

Sample prj here

【讨论】:

  • 是的,我知道这一点,但我需要避免这种情况。在 Unity 中可以做到。
  • 对不起,我不关注。您有 Unity 示例吗?
  • 我举了一个例子
猜你喜欢
  • 2018-04-05
  • 2023-03-12
  • 1970-01-01
  • 2020-10-13
  • 2020-06-21
  • 2018-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多