在Configure方法中使用服务时超出范围?

编程入门 行业动态 更新时间:2024-10-24 01:57:05
本文介绍了在Configure方法中使用服务时超出范围?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

下面是我的课本中的伪代码,我对在配置方法中使用服务感到困惑

Below is pseudo code from my textbook, and I'm confused about use a service in configure method

public class ConcreteA { public static Run(IServiceProvider serviceProvider) { ConcreteB _concrete = serviceProvider.GetRequiredService<ConcreteB>(); ... //use ConcreteB instance } } __________________________________________________________ // startup.cs public void ConfigureServices(IServiceCollection services) { services.AddScoped<ConcreteA>; services.AddScoped<ConcreteB>; } public void Configure(IApplicationBuilder app) { app.UseStatusCodePages(); app.UseDeveloperExceptionPage(); app.UseMvcWithDefaultRoute(); ConcreteA.Run(app.ApplicationServices); }

有人告诉我,因为我使用了 ConcreteA 在 Configure 中的方法中,所以我在范围之外运行它。我创建的任何依赖项(在这种情况下都是ConcreteB实例)都会徘徊。

I was told that becuase I use ConcreteA in Configure ,method, so I'm running this outside of a scope. Any dependency(ConcreteB instance in this case) I create will hang around.

我很困惑,下面是我的问题:

I'm very confused, below is my questions:

Q1-我将 ConcreteA 和 ConcreteB 注册为 AddScoped ,因此不应存在任何捕获的依赖项问题,因为它们在同一范围内,所以为什么 ConcreteB 仍然会徘徊。

Q1- I registered ConcreteA and ConcreteB both as AddScoped, so there shouldn't be any captured dependencies issues as they are in same scope, so why ConcreteB will still hang around.

Q2-我什至没有创建ConcreteA实例,因为我访问的方法是静态方法,因此需要创建否实例。因此, ConcreteB 甚至更不可能闲逛。

Q2- I didn't even create a ConcreteA instance as the method I access is a static method, so no ConcreteA instance needs to be created. So it is even more impossible for ConcreteB to hang around.

推荐答案

要明确回答您的困惑:您必须将服务提供者视为对象的缓存。当创建的服务未注册为临时服务时,它将在本地存储该实例,以便以后可以再次提供 same 实例。

To answer in regards to your confusion explicitly: You have to think about the service provider as a cache of objects. When it creates a service that is not registered as transient, then it will store that instance locally so that it can provide the same instance again at a later time.

例如,当您执行以下操作(假设 IFoo 未注册为瞬态)时,它将解析相同的对象实例:

For example, when you do the following (assuming IFoo is not registered as transient), then it will resolve the same object instance:

serviceProvider.GetService<IFoo>(); serviceProvider.GetService<IFoo>();

为此,服务提供商必须记住 IFoo 它在第一个调用中返回,因此它可以在第二个调用(以及任何其他调用)中返回相同的实例。

In order to do that, the service provider has to remember the IFoo it returned in the very first call, so it can return the same instance on the second call (and any other call).

那是什么一个范围?作用域基本上告诉服务提供商从单独缓存中解析服务。当您在范围内并且现在解析范围服务 IScopedBar 时,服务提供商为您创建的实例将被缓存在该范围缓存中:

So what is a scope? A scope basically tells the service provider to resolve services from a separate cache. When you are within a scope and you now resolve a scoped service IScopedBar, then the instance the service provider creates for you will be cached in that scoped cache:

serviceProvider.GetService<IScopedBar>(); serviceProvider.GetService<IScopedBar>();

当您在范围内并解析单例服务时,仍会查找该服务在主缓存中。但是,将在范围缓存中查找范围服务。

When you are within a scope and you resolve a singleton service, then that service will still be looked up in the main cache. But scoped services will be looked up in the scoped cache.

如果不关闭范围,那么一切都不会真正起作用。当关闭作用域时,这是在处置它时完成的(例如,当 using 块结束时),然后处置了作用域缓存中的服务并清除了缓存。但是,主缓存仍然保留。

That all wouldn’t really make a difference if a scope wouldn’t be closed. When a scope is closed, which is done when it gets disposed (e.g. when the using block ends), then the services in the scoped cache are disposed and the cache is cleared. The main cache however stays.

如果我们要在简化的伪服务提供程序类中实现它,则可能看起来像这样:

If we were to implement that in a simplified pseudo service provider class, it could look like this:

public class SimplifiedServiceProvider { private Dictionary<Type, object> mainCache = new Dictionary<Type, object>(); private Dictionary<Type, object> scopeCache = new Dictionary<Type, object>(); public object GetService(Type type) { var serviceLifetime = GetLifetimeForService(type); if (serviceLifetime == ServiceLifetime.Transient) { // transients are created directly return CreateNewInstance(type); } else if (serviceLifetime == ServiceLifetime.Singleton) { // try to get from the cache if (!mainCache.TryGetValue(type, out var service)) { // create the service first service = CreateNewInstance(type); mainCache.Add(type, service); } return service; } else if (serviceLifetime == ServiceLifetime.Scoped) { // try to get from the scope cache if (!scopeCache.TryGetValue(type, out var service)) { // create the service first service = CreateNewInstance(type); scopeCache.Add(type, service); } return service; } } public void DisposeScope() { // dispose all created (disposable) instances foreach (var instance in scopeCache.Values) (instance as IDisposable)?.Dispose(); // reset cache scopeCache.Clear(); } private ServiceLifetime GetLifetimeForService(Type type) { … } private object CreateNewInstance(Type type) { … } }

(服务提供者和服务范围的真正实现显然要复杂得多,但这仍然应该是一个好主意。

(The real implementation of a service provider and service scopes is obviously a bit more complicated than this, but this should still give a good idea of how scoped dependencies differ from singletons.)

牢记这个想法和伪实现,想象一下在范围之外解析范围服务时会发生什么,所以 DisposeScope 永远不会被调用:创建的作用域服务将永久保留在作用域缓存中;就像单例永久保留在主缓存中一样。

With that idea and pseudo implementation in mind, imagine what happens when you resolve a scoped service outside of a scope, so DisposeScope would never be called: The created scoped service would just stay permanently inside of the scope cache; just like singletons stay permanently within the main cache.

因此,通过在服务范围之外解析作用域服务 ,您可以有效地延长该实例最多是一个单例服务。这不会影响在范围内实际 创建的实例,但是在范围外创建的那些实例将在服务提供者的生存期内生存,通常是应用程序的生存期。

So by resolving a scoped service outside of a service scope, you effectively lifted the lifetime of that instance up to be a singleton service. This will not affect instances that actually are created within a scope, but those instances that are created outside of a scope will live for the lifetime of the service provider, which usually is the lifetime of the application.

这就是为什么当您要使用自然范围(即为您自动创建的范围,例如ASP)之外的范围服务时,通常希望创建一个临时范围的原因.NET Core在处理请求时会这样做。这样,您就可以限制该作用域的生存期,从而也可以限制要解析的实例的生存期。

That is why you usually want to create a temporary scope when you want to consume scoped services outside of "natural scopes" (i.e. scopes that are automatically created for you, like ASP.NET Core does when handling a request). That way, you restrict the lifetime of that scope, and as such also the lifetime of the instances that you resolve.

更多推荐

在Configure方法中使用服务时超出范围?

本文发布于:2023-11-16 20:46:59,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1607403.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:方法   Configure

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!