Roy*_*mir 5 c# dependency-injection .net-core asp.net-core
我使用 .net core 3.1 进行以下配置:
public interface IFoo
{
public void Work();
}
public class Foo : IFoo
{
readonly string MyGuid;
public Foo()
{
MyGuid = Guid.NewGuid().ToString();
}
public void Work() { Console.WriteLine(MyGuid); }
}
Run Code Online (Sandbox Code Playgroud)
这是配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IFoo, Foo>();
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IFoo foo, IServiceProvider myServiceProvider)
{
Console.WriteLine("Via ApplicationServices");
app.ApplicationServices.GetService<IFoo>().Work();
Console.WriteLine("Via IServiceProvider");
myServiceProvider.GetService<IFoo>().Work();
Console.WriteLine("Via IFoo injection");
foo.Work();
}
Run Code Online (Sandbox Code Playgroud)
结果是:
通过ApplicationServices 27e61428-2adf-4ffa-b27a-485b9c45471d <----不同
通过IServiceProvider c9e86865-2eeb-44db-b625-312f92533beb
通过IFoo注入c9e86865-2eeb-44db-b625-312f92533beb
更多,在控制器操作中,如果我使用IserviceProvider:
[HttpGet]
public IActionResult Get([FromServices] IServiceProvider serviceProvider)
{
serviceProvider.GetService<IFoo>().Work();
}
Run Code Online (Sandbox Code Playgroud)
我看到另一个不同的Guid 45d95a9d-4169-40a0-9eae-e29e85a3cc19:。
问题:
为什么方法中IServiceProvider的 和 Injection产生相同的 Guid ,而控制器的 action 和产生不同的?IFooConfigureapp.ApplicationServices.GetService
4此示例中有不同的指南
这是一项有范围的服务。它应该是同一个指南。
TL;博士;
IFoo foomyServiceProvider.GetService<IFoo>()在两者都传递到方法之前使用来解决Configure。因此,您第二次IFoo从同一个实例解析同一个实例。myServiceProvider
app.ApplicationServices是应用程序的特殊根服务提供者。父母myServiceProvider。因此它解决了不同的问题IFoo。
**当您尝试解析作用域服务时,默认行为应该是抛出异常。app.ApplicationServices
更长的解释
如果您有三个虚拟类:
class Singleton { }
class Scoped { }
class Transient { }
Run Code Online (Sandbox Code Playgroud)
然后您将它们注册为IServiceConfiguration:
public static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<Singleton>();
services.AddScoped<Scoped>();
services.AddTransient<Transient>();
}
Run Code Online (Sandbox Code Playgroud)
IServiceProvider现在,您在IServiceCollection命令行应用程序中创建“根” ,它看起来像这样:
ServiceCollection sc = new ServiceCollection();
ConfigureServices(sc);
ServiceProvider root = sc.BuildServiceProvider();
Run Code Online (Sandbox Code Playgroud)
根服务提供商行为(相当于app.ApplicationServices):
如果您现在测试root:
root.GetService<Singleton>();- 每次调用时都会返回相同的对象实例。root.GetService<Scoped>();- 每次调用时都会返回相同的对象实例。root.GetService<Transient>();每次调用都会返回新的对象实例。儿童范围的服务提供者行为(例如:IServiceProvider在Configure方法中):
如果您现在创建子作用域并使用它自己的IServiceProvider:
IServiceScope scope1 = root.CreateScope();
IServiceProvider sp1 = scope1.ServiceProvider;
Run Code Online (Sandbox Code Playgroud)
sp1.GetService<Singleton>();- 每次调用时都会返回相同的对象实例root.GetService<Singleton>();。Singleton无论您从哪个范围调用它,都是同一个实例。解决了将范围层次结构爬回到根服务提供者(无范围服务提供者)的问题。sp1.GetService<Scoped>();- 每次调用时都会返回相同的对象实例,但返回的实例不同root。对象实例缓存在当前范围内。每个作用域都会创建/缓存它自己的作用域实例。sp1.GetService<Transient>();每次调用它时都会返回新的对象实例,与根的行为相同。root作用域之所以“特殊”只是因为它没有父作用域,因此从root技术上解析作用域或单例服务会执行相同的操作 - 返回的对象实例缓存在其root自身中。
这也解释了为什么你不能直接解决服务IServiceCollection。IServiceCollection没有范围层次结构和缓存基础设施IServiceProvider。它只包含 的列表ServiceDescriptor。此外,还不清楚服务实例应该缓存在哪个范围内。
ASP.NET 核心
对于 ASP.NET Core 根目录IServiceProvider是app.ApplicationServices. 方法接收从应用程序范围Configure创建的第一个子范围。root对于每个 HTTP 请求,应用程序范围都会创建子范围,用于解析所有服务,并且其本身会注入到该 HTTP 请求的控制器和视图中。它还用于在控制器构造函数或视图中注入所有其他类型。
IFoo解决
因此,您的foofromConfigure方法是使用 解析的myServiceProvider,然后它们都用作 的输入参数Configure。框架做了这样的事情:
ServiceProvider root = sc.BuildServiceProvider(validateScopes: true);
var appScope = root.CreateScope();
IFoo foo = appScope.ServiceProvider.GetService<IFoo>();
ConfigureServices(foo, appScope.ServiceProvider);
Run Code Online (Sandbox Code Playgroud)
当您在方法sp.GetService<IFoo>()内部调用时,它与已经从外部调用的方法Configure相同。创建不同的实例,正如它应该的那样。appScope.ServiceProvider.GetService<IFoo>();root.GetService<IFoo>()IFoo
更多 ASP.NET Core:
为了防止开发人员在尝试解析scoped服务时犯错误app.ApplicationServices,并且没有意识到它是应用程序范围(全局),而不是 HTTP 请求范围,默认情况下,ASP.NET CoreServiceProvider使用BuildServiceProvider重载创建根:
ServiceProvider root = sc.BuildServiceProvider(validateScopes: true);
Run Code Online (Sandbox Code Playgroud)
validateScopes: true 执行检查,验证作用域服务永远不会从根提供者处解析;否则为假。
但是,这可能取决于您使用的兼容模式。我猜这就是它允许您通过 解决范围服务的原因app.ApplicationServices。
| 归档时间: |
|
| 查看次数: |
6467 次 |
| 最近记录: |