谁以及如何在依赖注入中初始化接口
Who and How initialize the Interface in Dependence Injection
对于Asp.Net核心依赖注入,我知道我们将依赖注册到IServiceCollection
,并使用IServiceProvider
来获取实例。
我想知道注册和初始化 IServiceCollection
的代码。
对于接口注入,为什么它知道从ServiceCollection中获取实例?哪个代码实现了这个功能?
我想知道全局控制器是谁以及如何控制它?
创建ASP.NET核心项目时,会为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 核心源代码中的调用链,请点击此处(包括 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);
}
// ...
}
为了补充已经提供的答案,在 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);
//...
}
唯一的区别是现在您必须自己创建集合,而不是框架在其管道中为您创建集合。
来自评论,
It bears mentioning that an ASP.NET Core app is nothing but a console app, which therefore explains why you can use IServiceColleciton
in a basic console app as well, or anywhere else you like, for that matter.
这是我在 .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;
}
}
}
对于Asp.Net核心依赖注入,我知道我们将依赖注册到IServiceCollection
,并使用IServiceProvider
来获取实例。
我想知道注册和初始化 IServiceCollection
的代码。
对于接口注入,为什么它知道从ServiceCollection中获取实例?哪个代码实现了这个功能?
我想知道全局控制器是谁以及如何控制它?
创建ASP.NET核心项目时,会为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 核心源代码中的调用链,请点击此处(包括 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);
}
// ...
}
为了补充已经提供的答案,在 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);
//...
}
唯一的区别是现在您必须自己创建集合,而不是框架在其管道中为您创建集合。
来自评论,
It bears mentioning that an ASP.NET Core app is nothing but a console app, which therefore explains why you can use
IServiceColleciton
in a basic console app as well, or anywhere else you like, for that matter.
这是我在 .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;
}
}
}