ASP.NET CurrentUICulture 在任务和 WebAPI 延迟结果中的行为不同
ASP.NET CurrentUICulture behaves differently in Task and WebAPI deferred result
我正在做一个 ASP.NET Web API 项目,在这个项目中我遇到了一个问题,其中 运行 异步的 child Task
s不继承 parent 线程的当前文化;即,即使在控制器构造函数中设置 Thread.CurrentThread.CurrentUICulture
之后,在操作中创建的任何 Task
默认情况下都具有不变文化,除非我单独设置它。这似乎已在框架 > 4.0 中修复,并且在将目标框架从 3.5.2
升级到 4.6.2
as mentioned here.
后工作正常
Starting with apps that target the .NET Framework 4.6, the calling thread's culture is inherited by each task, even if the task runs asynchronously on a thread pool thread.
现在任务中的文化继承按预期工作,我面临另一个奇怪的问题,该问题在 4.5.2 中不存在。如果 WebApi 操作结果的类型为 IEnumerable
,则结果将包含默认区域性。也许使用示例代码片段可以更好地解释这个问题:
public SampleController()
{
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo("ar-AE");
}
[Route]
public IHttpActionResult Get()
{
IEnumerable<Employee> employeesDeferred = BuildEmployees(true);
return Ok(employeesDeferred);
}
private IEnumerable<Employee> BuildEmployees(bool isDeferred)
{
var employees = Enumerable.Range(0, 2)
.Select(count => new Employee
{
Id = count++,
Culture = Thread.CurrentThread.CurrentUICulture.Name
});
if (isDeferred) { return employees; }
return employees.ToList();
}
请注意,我在构造函数中将 UI 文化设置为 "ar-AE"。 PFB 结果:
- 框架 4.5.2 - 所有员工的
Culture
将达到预期的 ar-AE
- 框架 4.6.2 - 所有员工的
Culture
将是 en-US(默认)
- framework 4.6.2 通过在结果中执行
.ToList()
(在上面的代码中调用 BuildEmployees(false)
而不是 BuildEmployees(true)
) - 所有员工的 Culture
将符合预期ar-AE
我确实进行了一些研究并看到了建议设置 NoAsyncCurrentCulture
开关的答案,例如,通过在应用程序设置中添加开关 <add key="appContext.SetSwitch:Switch.System.Globalization.NoAsyncCurrentCulture" value="true" />
- 但这会有点回滚到行为我们在 <4.0 中遇到了第一段中提到的任务中的文化继承问题。
我错过了什么?
更新:已验证上下文文化未在 Web 中发生 (JSON/XML) 序列化的线程中继承 API。
如问题中所述,调用线程的 UICulture 未流向执行序列化的线程。为了验证这一点,我创建了一个自定义 JsonConverter
(NewtonSoft) 并将其作为默认转换器添加到我的 WebAPI 并检查了 WriteJson
方法中的 UICulture - 正如预期的那样我设置的 UI文化是 overridden/lost 并且这个线程具有不变的文化。
我不想玩太多重写整个 JsonConverter
因此没有继续;相反,我需要的是在操作本身的上下文中强制序列化 API 的响应(UI 文化设置正确)。下面的自定义过滤器也实现了同样的效果,我在其中调用了响应内容的 LoadIntoBufferAsync()
:
/// <summary>
/// BUG Description and History:
/// We had an issue where the child Tasks/async operations were not inheriting the the current culture of the parent thread;
/// i.e., even after setting the Thread.CurrentThread.CurrentUICulture in the controller constructor, any Task created within the action was having the invariant culture by default
/// unless it is set it separately. This seems to have fixed in framework > 4.0 and was working fine after upgrading the target framework from 3.5.2 to 4.6.2
/// ref - https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-based-asynchronous-programming
/// But with this fix in framework, there introduced an unnoticed? bug where in the UI culture do not flow from the calling thread's context to the NewtonSoft Json Serializer write
/// And hence, any deferred serialization (like IEnumerable) will run under the Invariant Culture (en-US) thus ending up picking the english resource file instead of the culture set for the thread.
/// This works fine in framework 3.5.2 or if we enable the "Switch.System.Globalization.NoAsyncCurrentCulture" switch in 4.6.2. But using the switch will diable the flow of culture in async operations and will end up having the issue
/// we had in 3.5.2.
/// Inorder to fix this issue, the workaround is to force the serialization happen in the action context itself where the thread UI culture is the one we have set.
/// </summary>
public class ForceSerializeHttpContentFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.Response.Content.LoadIntoBufferAsync().Wait();
}
}
不确定这是否是正确的修复;等待社区的更多回应。谢谢。
我正在做一个 ASP.NET Web API 项目,在这个项目中我遇到了一个问题,其中 运行 异步的 child Task
s不继承 parent 线程的当前文化;即,即使在控制器构造函数中设置 Thread.CurrentThread.CurrentUICulture
之后,在操作中创建的任何 Task
默认情况下都具有不变文化,除非我单独设置它。这似乎已在框架 > 4.0 中修复,并且在将目标框架从 3.5.2
升级到 4.6.2
as mentioned here.
Starting with apps that target the .NET Framework 4.6, the calling thread's culture is inherited by each task, even if the task runs asynchronously on a thread pool thread.
现在任务中的文化继承按预期工作,我面临另一个奇怪的问题,该问题在 4.5.2 中不存在。如果 WebApi 操作结果的类型为 IEnumerable
,则结果将包含默认区域性。也许使用示例代码片段可以更好地解释这个问题:
public SampleController()
{
System.Threading.Thread.CurrentThread.CurrentUICulture =
new System.Globalization.CultureInfo("ar-AE");
}
[Route]
public IHttpActionResult Get()
{
IEnumerable<Employee> employeesDeferred = BuildEmployees(true);
return Ok(employeesDeferred);
}
private IEnumerable<Employee> BuildEmployees(bool isDeferred)
{
var employees = Enumerable.Range(0, 2)
.Select(count => new Employee
{
Id = count++,
Culture = Thread.CurrentThread.CurrentUICulture.Name
});
if (isDeferred) { return employees; }
return employees.ToList();
}
请注意,我在构造函数中将 UI 文化设置为 "ar-AE"。 PFB 结果:
- 框架 4.5.2 - 所有员工的
Culture
将达到预期的 ar-AE - 框架 4.6.2 - 所有员工的
Culture
将是 en-US(默认) - framework 4.6.2 通过在结果中执行
.ToList()
(在上面的代码中调用BuildEmployees(false)
而不是BuildEmployees(true)
) - 所有员工的Culture
将符合预期ar-AE
我确实进行了一些研究并看到了建议设置 NoAsyncCurrentCulture
开关的答案,例如,通过在应用程序设置中添加开关 <add key="appContext.SetSwitch:Switch.System.Globalization.NoAsyncCurrentCulture" value="true" />
- 但这会有点回滚到行为我们在 <4.0 中遇到了第一段中提到的任务中的文化继承问题。
我错过了什么?
更新:已验证上下文文化未在 Web 中发生 (JSON/XML) 序列化的线程中继承 API。
如问题中所述,调用线程的 UICulture 未流向执行序列化的线程。为了验证这一点,我创建了一个自定义 JsonConverter
(NewtonSoft) 并将其作为默认转换器添加到我的 WebAPI 并检查了 WriteJson
方法中的 UICulture - 正如预期的那样我设置的 UI文化是 overridden/lost 并且这个线程具有不变的文化。
我不想玩太多重写整个 JsonConverter
因此没有继续;相反,我需要的是在操作本身的上下文中强制序列化 API 的响应(UI 文化设置正确)。下面的自定义过滤器也实现了同样的效果,我在其中调用了响应内容的 LoadIntoBufferAsync()
:
/// <summary>
/// BUG Description and History:
/// We had an issue where the child Tasks/async operations were not inheriting the the current culture of the parent thread;
/// i.e., even after setting the Thread.CurrentThread.CurrentUICulture in the controller constructor, any Task created within the action was having the invariant culture by default
/// unless it is set it separately. This seems to have fixed in framework > 4.0 and was working fine after upgrading the target framework from 3.5.2 to 4.6.2
/// ref - https://docs.microsoft.com/en-us/dotnet/standard/parallel-programming/task-based-asynchronous-programming
/// But with this fix in framework, there introduced an unnoticed? bug where in the UI culture do not flow from the calling thread's context to the NewtonSoft Json Serializer write
/// And hence, any deferred serialization (like IEnumerable) will run under the Invariant Culture (en-US) thus ending up picking the english resource file instead of the culture set for the thread.
/// This works fine in framework 3.5.2 or if we enable the "Switch.System.Globalization.NoAsyncCurrentCulture" switch in 4.6.2. But using the switch will diable the flow of culture in async operations and will end up having the issue
/// we had in 3.5.2.
/// Inorder to fix this issue, the workaround is to force the serialization happen in the action context itself where the thread UI culture is the one we have set.
/// </summary>
public class ForceSerializeHttpContentFilter : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
filterContext.Response.Content.LoadIntoBufferAsync().Wait();
}
}
不确定这是否是正确的修复;等待社区的更多回应。谢谢。