gpt4 book ai didi

c# - asp.net core (3+) CreateScope() 上的共享上下文

转载 作者:行者123 更新时间:2023-12-01 22:17:12 31 4
gpt4 key购买 nike

当我尝试运行后台任务时,我总是在该任务内创建一个新范围。随着更新到 3+,似乎在新的创建范围内,存在对原始请求的引用。以下代码将在 Debugger.Break() 语句上中断:

public class TestController : Controller
{
public readonly IServiceScopeFactory ServiceScopeFactory;

public TestController(
IServiceScopeFactory serviceScopeFactory)
{
this.ServiceScopeFactory = serviceScopeFactory;
}

// GET
public IActionResult Index()
{
Task.Run(() =>
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var actionContextAccessor = scope.ServiceProvider.GetService<IActionContextAccessor>();
var actionContext = actionContextAccessor.ActionContext;

if (actionContext.ActionDescriptor != null)
Debugger.Break();
}
});

return Content("Test");
}
}

启动看起来像这样:

public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}

问题在于 httpContext 与新创建的作用域共享。当其中一个作用域被废弃时,它会影响另一个作用域。例如,使用 IUrlHelper,会导致“IFeatureCollection 已被处理”。

为了测试,我添加了一个测试 httpContext 是否相同。看来确实如此!

public IActionResult Index()
{
// Just for testing
var originalContext = this.HttpContext;

Task.Run(() =>
{
using (var scope = ServiceScopeFactory.CreateScope())
{
// Make sure the original request was disposed
Thread.Sleep(1000);

var actionContextAccessor = scope.ServiceProvider.GetService<IActionContextAccessor>();
var actionContext = actionContextAccessor.ActionContext;

if (originalContext == actionContext.HttpContext)
Debugger.Break();
}
});

return Content("Test");
}

对我来说,这似乎是奇怪的行为,因为我希望新范围不具有相同的 httpContext。它应该是一个新的范围。应该以其他方式创建作用域吗?

找到解决方案

在我的生产代码中,我使用 transient ActionContext 作用域,它尝试检测它是否正在处理请求或后台作用域,如下所示:

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddTransient<ActionContext>((s) => {
var actionContextAccessor = serviceProvider.GetRequiredService<IActionContextAccessor>();
var actionContext = actionContextAccessor?.ActionContext;

// Create custom actioncontext
if (actionContext == null) {
// create a manual actionContext
}


return actionContext;
});

这似乎不再起作用了。如果 httpContext 通过 IHttpContextAccessor 存在,该解决方案似乎过于验证:

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>()
.AddTransient<ActionContext>((s) => {
var currentContextAccess = serviceProvider.GetService<IHttpContextAccessor>();
if (currentContextAccess.HttpContext == null) {
// create a manual actionContext
...

return actionContext;
}

var actionContextAccessor = serviceProvider.GetRequiredService<IActionContextAccessor>();
return actionContextAccessor.ActionContext;
});

最佳答案

For me, this seems like odd behaviour, cause I would except the scope not to be. Should the scope be created in another way?

为什么奇怪? IActionContextAccessor 是一个单例(与 IHttpContextAccessor 相同),因此即使在新创建的范围内也通常会返回相同的实例。

由于您没有等待 Task.Run,因此您的请求将在任务完成之前完成。请求完成后你想如何访问HttpContext?仅在请求期间有效。您必须在启动新任务之前获取所有必需的数据,并将所需的值传递给后台任务。

HttpContext 仅在请求期间有效,并且由于您不等待它,因此请求会提前结束。

您的代码所做的是未定义的行为,请参阅 David 的指南

关于c# - asp.net core (3+) CreateScope() 上的共享上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59985231/

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