我有以下情况:
builder.Services.AddHttpClient...
.AddHttpMessageHandler<CustomMessageHandler>();
builder.Services.AddScoped<ScopedService>();
此作用域服务被注入到消息处理程序和页面代码中。 我的问题是对象不一样。有两个独立的作用域和两个独立的 ScopedService 实例。
第一个也是最明显的解决方案是将服务作为单例注入。 在工作解决方案时,这是不行的,因为许多服务或库都有“AddSomething”,其后面有“AddScoped”。
我发现的第二个解决方案是推荐 SuppressHandlerScope: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.http.httpclientfactoryoptions.suppresshandlerscope?view=dotnet-plat-ext-8.0
也不起作用,因为它无法从根访问范围服务。
我发现的第三个解决方案是推荐 IHttpContextAccessor,但是这里:https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-context?view=aspnetcore-6.0#ihttpcontextaccessorhttpcontext-in-razor -components-blazor,我有点担心。
我愿意:
防止在 WebAssembly 应用程序中创建第二个作用域。
或者
从 DelegatingHandler 访问页面正在使用的相同范围。
(或者如何避免为每个注入服务创建多个实例的任何其他建议)
编辑:为什么这是一个问题? 具体来说,我正在使用组件库。该库注入范围服务。其中一项范围服务有一个项目列表。页面上的组件使用服务中的此列表。
显然修改此列表的副本对组件没有任何好处。
该服务获得两个实例,因为它已确定作用域,并且 HttpClientFactory 正在创建另一个作用域。
抑制范围创建选项,使构建器跳过“CreateScope()”,但构建器本身是单例的,因此您不能再使用范围。
我想强制 HttpClient 使用与 WebAssembly 相同的范围,但似乎没有任何解决方案。
最好的解决方案是重新考虑你的设计,但如果不可能,你可以尝试像
ScopeHolder
注入 .net 的 IServiceScopeFactory
:
public class CustomScopeHolder
{
private readonly IServiceScopeFactory _scopeFactory;
private IServiceScope _scope;
public CustomScopeHolder(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
public void CreateScope()
{
_scope = _scopeFactory.CreateScope();
}
public T GetService<T>()
{
return _scope.ServiceProvider.GetRequiredService<T>();
}
当然将其注册为单例:
services.AddSingleton<CustomScopeHolder>();
您可以在代码页+自定义消息的生命周期中使用它(也许通过中间件?):
var scopeHolder = context.RequestServices.GetRequiredService<CustomScopeHolder>();
scopeHolder.CreateScope();
然后你可以轻松地将它注入(通过构造函数或其他方式):
1. code page
2. custom massage
并像这样使用它:
var scopedService = _scopeHolder.GetService<ScopedService>();