gpt4 book ai didi

c# - ApplicationServices 解析网络核心中不同范围的实例?

转载 作者:行者123 更新时间:2023-12-04 00:50:20 26 4
gpt4 key购买 nike

我正在使用具有此配置的 .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); }
}
这是配置:
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();

}
结果是:

Via ApplicationServices 27e61428-2adf-4ffa-b27a-485b9c45471d <----different
Via IServiceProvider c9e86865-2eeb-44db-b625-312f92533beb
Via IFoo injection c9e86865-2eeb-44db-b625-312f92533beb


更多,在 Controller Action 中,如果我使用 IserviceProvider :
   [HttpGet]
public IActionResult Get([FromServices] IServiceProvider serviceProvider)
{
serviceProvider.GetService<IFoo>().Work();
}
我看到另一个不同的 Guid: 45d95a9d-4169-40a0-9eae-e29e85a3cc19 .
问题:
为什么 IServiceProvider和注入(inject) IFooConfigure方法产生相同的 Guid ,而 Controller Action 和 app.ApplicationServices.GetService产生不同的?
4此示例中的不同指南
这是一个范围服务。它应该是同一个Guid。

最佳答案

TL;博士; IFoo foo使用 myServiceProvider.GetService<IFoo>() 解决在两者都被传递到 Configure 之前方法。所以你正在解决相同的IFoo来自同一 myServiceProvider 的实例例如第二次。app.ApplicationServices是应用程序的特殊根服务提供者。 myServiceProvider 的父级.因此它解决了不同的IFoo .
**app.ApplicationServices 的默认行为|当您尝试解析范围服务时应该抛出异常。
更长的解释
如果你有三个虚拟类:

class Singleton { }
class Scoped { }
class Transient { }
然后您在 IServiceConfiguration 中注册它们:
public static void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<Singleton>();
services.AddScoped<Scoped>();
services.AddTransient<Transient>();
}
现在,你创建你的“根” IServiceProvider来自 IServiceCollection - 在命令行应用程序中,它看起来像这样:
ServiceCollection sc = new ServiceCollection();
ConfigureServices(sc);
ServiceProvider root = sc.BuildServiceProvider();
根服务提供者行为(相当于 app.ApplicationServices ):
如果您现在测试 root :
  • root.GetService<Singleton>(); - 每次调用它都会返回相同的对象实例。
  • root.GetService<Scoped>(); - 每次调用它都会返回相同的对象实例。
  • root.GetService<Transient>();每次调用它都会返回新的对象实例。

  • child 范围服务提供者行为(例如: IServiceProviderConfigure 方法中):
    如果您现在创建子作用域并使用它自己的 IServiceProvider :
    IServiceScope scope1 = root.CreateScope();
    IServiceProvider sp1 = scope1.ServiceProvider;
  • 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 根 IServiceProviderapp.ApplicationServices . Configure方法接收从 root 创建的第一个子范围- 应用范围。对于每个 HTTP 请求,应用程序范围创建用于解析所有服务的子范围,并且它本身被注入(inject)到该 HTTP 请求的 Controller 和 View 中。它还用于在 Controller 构造函数或 View 中注入(inject)所有其他类型。
    IFoo分辨率
    所以,你的 foo来自 Configure方法使用 myServiceProvider 解决, 然后它们都被用作 Configure 的输入参数.框架做这样的事情:
    ServiceProvider root = sc.BuildServiceProvider(validateScopes: true);
    var appScope = root.CreateScope();
    IFoo foo = appScope.ServiceProvider.GetService<IFoo>();
    ConfigureServices(foo, appScope.ServiceProvider);

    当您调用 sp.GetService<IFoo>() Configure 内部方法与 appScope.ServiceProvider.GetService<IFoo>(); 相同那已经从外面叫了。 root.GetService<IFoo>()创造不同 IFoo例如,它应该。
    更多 ASP.NET 核心:
    为防止开发人员在尝试解决 scoped 时出错来自 app.ApplicationServices 的服务并且没有意识到它是应用程序范围(全局),而不是范围为 HTTP 请求,默认情况下,ASP.NET Core 创建根 ServiceProvider使用 BuildServiceProvider重载:
    ServiceProvider root = sc.BuildServiceProvider(validateScopes: true);

    validateScopes: true to perform check verifying that scoped services never gets resolved from root provider; otherwise false.


    但是,这可能取决于您使用的兼容模式。我猜这就是它允许您通过 app.ApplicationServices 解析范围服务的原因。 .

    关于c# - ApplicationServices 解析网络核心中不同范围的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67146454/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com