Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# CreateScope()上的asp.net核心(3+;)共享上下文_C#_Asp.net Core - Fatal编程技术网

C# CreateScope()上的asp.net核心(3+;)共享上下文

C# CreateScope()上的asp.net核心(3+;)共享上下文,c#,asp.net-core,C#,Asp.net Core,当我尝试运行后台任务时,我总是在该任务内创建一个新的作用域。随着3+的更新,似乎在新的create范围内,有一个对原始请求的引用。以下代码将在Debugger.break()语句上中断: public class TestController : Controller { public readonly IServiceScopeFactory ServiceScopeFactory; public TestController( IServiceScopeFa

当我尝试运行后台任务时,我总是在该任务内创建一个新的作用域。随着3+的更新,似乎在新的create范围内,有一个对原始请求的引用。以下代码将在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");
    }
}
公共类TestController:Controller
{
公共只读IServiceScopeFactory服务ScopeFactory;
公共测试控制器(
IServiceScopeFactory服务范围工厂)
{
this.ServiceScopeFactory=ServiceScopeFactory;
}
//得到
公共IActionResult索引()
{
Task.Run(()=>
{
使用(var scope=ServiceScopeFactory.CreateScope())
{
var actionContextAccessor=scope.ServiceProvider.GetService();
var actionContext=actionContextAccessor.actionContext;
if(actionContext.ActionDescriptor!=null)
Debugger.Break();
}
});
返回内容(“测试”);
}
}
启动过程如下所示:

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?}");
        });
    }
}
公共类启动
{
public void配置服务(IServiceCollection服务)
{
services.AddControllers();
services.AddSingleton();
}
public void配置(IApplicationBuilder应用程序、IWebHostEnvironment环境)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(端点=>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
名称:“默认”,
模式:“{controller=Home}/{action=Index}/{id?}”);
});
}
}
问题是httpContext与新的create作用域共享。当处理其中一个作用域时,它会影响另一个作用域。例如,使用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");
}
public IActionResult Index()
{
//只是为了测试
var originalContext=this.HttpContext;
Task.Run(()=>
{
使用(var scope=ServiceScopeFactory.CreateScope())
{
//确保原始请求已被处理
睡眠(1000);
var actionContextAccessor=scope.ServiceProvider.GetService();
var actionContext=actionContextAccessor.actionContext;
if(originalContext==actionContext.HttpContext)
Debugger.Break();
}
});
返回内容(“测试”);
}
对我来说,这似乎是一种奇怪的行为,因为除了新的作用域之外,我不希望有相同的httpContext。这应该是一个新的范围。是否应该以另一种方式创建范围

找到解决方案 在我的生产代码中,我使用了一个瞬态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;
    }); 
services.AddSingleton()
.AddTransient((s)=>{
var actionContextAccessor=serviceProvider.GetRequiredService();
var actionContext=actionContextAccessor?.actionContext;
//创建自定义actioncontext
if(actionContext==null){
//创建手动操作上下文
}
返回上下文;
}); 
这似乎不再管用了。如果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;
    }); 
services.AddSingleton()
.AddTransient((s)=>{
var currentContextAccess=serviceProvider.GetService();
如果(currentContextAccess.HttpContext==null){
//创建手动操作上下文
...
返回上下文;
}
var actionContextAccessor=serviceProvider.GetRequiredService();
返回actionContextAccessor.ActionContext;
}); 
对我来说,这似乎是一种奇怪的行为,因为我不希望出现这种情况。是否应该以另一种方式创建范围

为什么奇怪
IActionContextAccessor
是一个单例(与IHttpContextAccessor相同),因此即使在新创建的作用域内,返回相同的实例也是正常的

由于您没有等待
任务。请运行
,您的请求将在任务完成之前完成。请求完成后,您希望如何访问HttpContext?它只在请求期间有效。在启动新任务之前,必须获得所有必需的数据,并将所需的值传递给后台任务

HttpContext
仅在请求期间有效,因为您不等待请求,所以请求提前结束

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


为什么奇怪?上下文访问器是一个单例(与IHttpContextAccessor相同),因此即使在范围内也返回相同的实例是正常的。还有,你想要实现什么?由于您没有等待
任务。运行
,您的请求将在任务完成之前完成,因此您希望访问什么?HttpContext仅在请求期间有效,因为您不等待它,请求会提前结束,因此其未定义的行为,请参阅David的指南,我的期望是actionContext.HttpContext为空。由于它位于asp.net core 2.2Again上,因此它的行为未定义。做不依靠在…上未定义。行为。这就是为什么不能保证它在两个版本之间保持不变。只是不要使用未定义的行为(参见链接指南)。未定义的行为意味着如果使用它,任何事情都可能发生。您可以获取null、相同的上下文(在处置之前)或来自不同线程的上下文。它没有定义。这只是为了演示。我的问题是,当我在另一个线程(本例中的任务)中创建一个新范围时,为什么会有一个(相同的)上下文