谁以及如何在依赖注入中初始化接口

时间:2018-04-17 09:52:12

标签: c# dependency-injection inversion-of-control asp.net-core-2.0 ioc-container

对于Asp.Net Core Dependence Injection,我知道我们将依赖注册到IServiceCollection,并使用IServiceProvider来获取实例。

我想知道注册和初始化IServiceCollection的代码。

对于Interface Injection,为什么知道从ServiceCollection获取实例?哪个代码实现了这个功能?

我想知道全局控制器谁以及如何控制它?

3 个答案:

答案 0 :(得分:1)

创建ASP.NET Core项目时,会为Program.Main()生成以下代码:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .Build();
}

IServiceCollection的实例是在WebHost.CreateDefaultBuilder(args)内创建的,然后传递给Startup.ConfigureServices(IServiceCollection services)来电。

如果你想在ASP.NET Core源代码中跟踪调用链,这里是(包含github上的源代码的链接):

WebHost.CreateDefaultBuilder()调用WebHostBuilderExtensions.UseDefaultServiceProvider()扩展方法:

public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
    var builder = new WebHostBuilder()

        .UseIISIntegration()
        // ...
        .UseDefaultServiceProvider((context, options) =>
        {
            options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
        });

        // ...

    return builder;
}

WebHostBuilderExtensions.UseDefaultServiceProvider()调用WebHostBuilder.ConfigureServices()方法:

public static IWebHostBuilder UseDefaultServiceProvider(this IWebHostBuilder hostBuilder, Action<WebHostBuilderContext, ServiceProviderOptions> configure)
{
    return hostBuilder.ConfigureServices((context, services) =>
    {
        var options = new ServiceProviderOptions();
        configure(context, options);
        services.Replace(ServiceDescriptor.Singleton<IServiceProviderFactory<IServiceCollection>>(new DefaultServiceProviderFactory(options)));
    });
}

WebHostBuilder最终会创建ServiceCollection的实例并调用Startup.ConfigureServices()方法(通过存储操作):

private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
{
    //  ...

    // Creation of `ServiceCollection` instance
    var services = new ServiceCollection();

    //  ...

    foreach (var configureServices in _configureServicesDelegates)
    {
        configureServices(_context, services);
    }

    //  ...
}

答案 1 :(得分:1)

为了补充已经提供的答案,在asp.net-core之外,DI框架可以单独使用,因为它是一个完全解耦的模块。

Essential .NET - Dependency Injection with .NET Core

public static void Main() {
    IServiceCollection serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
    var application = new MyApplication(serviceCollection);

    // Run
    // ...
}

static private void ConfigureServices(IServiceCollection services) {
    ILoggerFactory loggerFactory = new Logging.LoggerFactory();
    services.AddInstance<ILoggerFactory>(loggerFactory);

    //...
}

唯一的区别是,现在你必须自己创建集合,而不是作为管道的一部分为你做框架。

来自评论,

  

值得一提的是,ASP.NET核心应用程序只不过是一个控制台应用程序,因此可以解释为什么您可以在基本控制台应用程序中使用IServiceColleciton,或者在其他任何您喜欢的地方使用它。

答案 2 :(得分:0)

这是我在.net core 2.2上执行的操作:

using System;
using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;

namespace ConsoleAppDependencyInjection
{
    class Program
    {
        static void Main(string[] args)
        {
            var serviceProvider = ConfigureContainer();
            var service1 = serviceProvider.GetService<Service1>();
            var service2 = serviceProvider.GetService<Service2>();

            Debug.Assert(service1 != null);
            Debug.Assert(service2 != null);
        }

        static IServiceProvider ConfigureContainer()
        {
            var services = new ServiceCollection();
            ConfigureServices(services);
            return services.BuildServiceProvider();
        }

        static void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<Service1>();
            services.AddSingleton<Service2>();
        }
    }

    public class Service1
    {
        public Service1()
        {
        }
    }

    public class Service2
    {
        Service1 service1;
        public Service2(Service1 service1)
        {
            this.service1 = service1;
        }
    }
}