Asp.net core 异步本地<;T>;不';t到达控制器
我不完全理解这种情况,其中AsyncLocal设置在中的某个点,但在将其注入到中时未到达控制器 我已经使它与工作原理相似,但仍然不太接近。但是,如果我从设置AsyncLocal,它将到达控制器。另外,设置HttpContext.Items属性也可以 问题:HttpContext如何能够始终保留Items属性内容,并且ASP.NET运行时是否出于某些安全原因处理my DomainContextAccessor捕获的ExecutionContext,因为它设置在何处Asp.net core 异步本地<;T>;不';t到达控制器,asp.net-core,asp.net-web-api,Asp.net Core,Asp.net Web Api,我不完全理解这种情况,其中AsyncLocal设置在中的某个点,但在将其注入到中时未到达控制器 我已经使它与工作原理相似,但仍然不太接近。但是,如果我从设置AsyncLocal,它将到达控制器。另外,设置HttpContext.Items属性也可以 问题:HttpContext如何能够始终保留Items属性内容,并且ASP.NET运行时是否出于某些安全原因处理my DomainContextAccessor捕获的ExecutionContext,因为它设置在何处 我已经做了一个演示来演示这个用例
我已经做了一个演示来演示这个用例。我真的很感激有人能告诉我这个问题。所以必须发生的是,执行上下文的改变会抹去这个值。它在中间件中工作,因为控制器与中间件处于相同的执行上下文中 将代码更改为:
私有静态void DomainContextChangeHandler(AsyncLocalValueChangedArgs args)
{
Trace.WriteLine($“ThreadContextChanged:{args.ThreadContextChanged}”);
Trace.WriteLine($“Current:{args.CurrentValue?.GetHashCode()}”);
Trace.WriteLine($“Previous:{args.PreviousValue?.GetHashCode()}”);
Trace.WriteLine($“线程Id:{Thread.CurrentThread.ManagedThreadId}”);
}
现在您可以看到上下文何时更改
以下是您可以做的事情:
私有静态void DomainContextChangeHandler(AsyncLocalValueChangedArgs args)
{
如果(args.ThreadContextChanged&&(args.PreviousValue!=null)&&(args.CurrentValue==null))
{
Trace.WriteLine(
“****检测到具有以前值但设置为当前值的上下文更改”+
“值为空。将值重置为上一个。”);
_domainContextCurrent.Value=args.PreviousValue;
返回;
}
Trace.WriteLine($“ThreadContextChanged:{args.ThreadContextChanged}”);
Trace.WriteLine($“Current:{args.CurrentValue?.GetHashCode()}”);
Trace.WriteLine($“Previous:{args.PreviousValue?.GetHashCode()}”);
Trace.WriteLine($“线程Id:{Thread.CurrentThread.ManagedThreadId}”);
}
但是,这有点违背了使用asynchlocal
作为备份存储的目的
我的建议是删除AsyncLocal
,使用普通的类作用域存储:
名称空间WebApp.Models
{
公共接口IDomainContextAccessor
{
DomainContext DomainContext{get;set;}
}
公共密封类DomainContextAccessor:IDomainContextAccessor
{
公共域上下文域上下文{get;set;}
}
}
并将其作为作用域而不是单例注入:
services.AddScoped<IDomainContextAccessor, DomainContextAccessor>();
services.addScope();
它会做你想要的事情,而不会有任何混乱——而且,未来你(或开发人员)将完全理解正在发生的事情以及为什么会是这样
没有中间件,没有
AsyncLocal
有趣的业务。它只是起作用。所以必须发生的是执行上下文的更改会清除该值。它在中间件中工作,因为控制器与中间件处于相同的执行上下文中
将代码更改为:
私有静态void DomainContextChangeHandler(AsyncLocalValueChangedArgs args)
{
Trace.WriteLine($“ThreadContextChanged:{args.ThreadContextChanged}”);
Trace.WriteLine($“Current:{args.CurrentValue?.GetHashCode()}”);
Trace.WriteLine($“Previous:{args.PreviousValue?.GetHashCode()}”);
Trace.WriteLine($“线程Id:{Thread.CurrentThread.ManagedThreadId}”);
}
现在您可以看到上下文何时更改
以下是您可以做的事情:
私有静态void DomainContextChangeHandler(AsyncLocalValueChangedArgs args)
{
如果(args.ThreadContextChanged&&(args.PreviousValue!=null)&&(args.CurrentValue==null))
{
Trace.WriteLine(
“****检测到具有以前值但设置为当前值的上下文更改”+
“值为空。将值重置为上一个。”);
_domainContextCurrent.Value=args.PreviousValue;
返回;
}
Trace.WriteLine($“ThreadContextChanged:{args.ThreadContextChanged}”);
Trace.WriteLine($“Current:{args.CurrentValue?.GetHashCode()}”);
Trace.WriteLine($“Previous:{args.PreviousValue?.GetHashCode()}”);
Trace.WriteLine($“线程Id:{Thread.CurrentThread.ManagedThreadId}”);
}
但是,这有点违背了使用asynchlocal
作为备份存储的目的
我的建议是删除AsyncLocal
,使用普通的类作用域存储:
名称空间WebApp.Models
{
公共接口IDomainContextAccessor
{
DomainContext DomainContext{get;set;}
}
公共密封类DomainContextAccessor:IDomainContextAccessor
{
公共域上下文域上下文{get;set;}
}
}
并将其作为作用域而不是单例注入:
services.AddScoped<IDomainContextAccessor, DomainContextAccessor>();
services.addScope();
它会做你想要的事情,而不会有任何混乱——而且,未来你(或开发人员)将完全理解正在发生的事情以及为什么会是这样
没有中间件,没有
AsyncLocal
有趣的业务。它只是起作用。关于“我应该如何解决这个问题?”您已经有了一个很好的答案,下面是对它为什么会出现这种情况的更多描述
AsyncLocal
的语义与相同。因为它具有相同的语义,所以我总是喜欢将它与IDisposable
一起使用,这样范围就清晰明确,并且对于方法是否标记为async
没有奇怪的规则
有关奇怪规则的详细信息,请参阅。总之:
- 将新值写入
将在当前范围内设置该值AsyncLocal
- 标记为
的方法将在第一个ti时将其作用域复制到新作用域async
using (MyImplicitValue.Set(myValue)) { // Code in here can get myValue from MyImplicitValue.Get(). }
public async Task InvokeAsync(HttpContext context) { using (implicitValue.Set(myValue)) { await _next(context); } }