![](/img/trans.png)
[英]How to handle shared data between the controller and the view in ASP.NET MVC?
[英]ASP.NET MVC (Async) CurrentCulture is not shared between Controller and View
我有一个针对.NET Framework 4.7.1的ASP.NET MVC 4应用程序,如果操作包含异步调用,则存在Controller和View之间不共享文化的问题。
我引用了NuGet包Microsoft.AspNet.Mvc
5.2.3(可以在5.2.4中复制)。
这是Controller中的代码:
public class CulturesTestController : Controller
{
public async Task<ActionResult> Index(string value)
{
Thread.CurrentThread.CurrentCulture =
CultureInfo.GetCultureInfo("fi-FI");
Thread.CurrentThread.CurrentUICulture =
CultureInfo.GetCultureInfo("fi-FI");
var model = new CulturesContainer
{
CurrentCulture = Thread.CurrentThread.CurrentCulture,
CurrentUICulture = Thread.CurrentThread.CurrentUICulture,
CurrentThreadId = Thread.CurrentThread.ManagedThreadId
};
Log.Write(Level.Info, "CurrentUICulture - Before Await - " +
"CurrentCulture: " +
$"{Thread.CurrentThread.CurrentCulture}, " +
"CurrentUICulture: "
${Thread.CurrentThread.CurrentUICulture} -> "+
"ThreadId: " +
$"{Thread.CurrentThread.ManagedThreadId}");
await GetAwait();
Log.Write(Level.Info, "CurrentUICulture - After Await - " +
"CurrentCulture: " +
$"{Thread.CurrentThread.CurrentCulture}, " +
"CurrentUICulture: " +
$"{Thread.CurrentThread.CurrentUICulture} -> " +
"ThreadId: " +
$"{Thread.CurrentThread.ManagedThreadId}");
return View("Index", model);
}
public class CulturesContainer
{
public CultureInfo CurrentCulture { get; set; }
public int CurrentThreadId { get; set; }
public CultureInfo CurrentUICulture { get; set; }
}
private async Task GetAwait()
{
await Task.Yield();
}
}
这是View中的代码:
@using System.Globalization
@using System.Threading
@model CultureTest.Controllers.CulturesTestController.CulturesContainer
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>title</title>
</head>
<body>
<div>
InitialCurrentCulture = {
<label>@Html.Raw(Model.CurrentCulture)</label>
} --
InitialCurrentUICulture = {
<label>@Html.Raw(Model.CurrentUICulture)</label>
} --
InitialThreadId = {
<label>@Html.Raw(Model.CurrentThreadId)</label>
}
<br />
ActualCurrentCulture = {
<label>@Html.Raw(CultureInfo.CurrentCulture)</label>
} --
ActualCurrentUICulture = {
<label>@Html.Raw(CultureInfo.CurrentUICulture)</label>
} --
ActualThreadId = {
<label>@Html.Raw(Thread.CurrentThread.ManagedThreadId)</label>
}
</div>
</body>
</html>
日志如下:
20180320-12:04:25.357-12 -INFO -CulturesTestController+<Index>d__0:
CurrentUICulture - Before Await -
CurrentCulture: fi-FI, CurrentUICulture: fi-FI -> ThreadId: 12
20180320-12:04:25.357-8 -INFO -CulturesTestController+<Index>d__0:
CurrentUICulture - After Await -
CurrentCulture: fi-FI, CurrentUICulture: fi-FI -> ThreadId: 8
网页显示:
InitialCurrentCulture = { fi-FI } --
InitialCurrentUICulture = { fi-FI } -- InitialThreadId = { 12 }
ActualCurrentCulture = { en-US } --
ActualCurrentUICulture = { en-US } -- ActualThreadId = { 9 }
.NET Framework <4.6中存在一个问题,已在4.6中修复,但似乎问题仍然存在于MVC中。
如果线程是执行基于任务的异步操作的线程池线程,并且应用程序面向.NET Framework 4.6或更高版本的.NET Framework,则其UI文化由调用线程的UI文化决定。 (来源https://msdn.microsoft.com/en-us/library/system.globalization.cultureinfo.currentuiculture(v=vs.110).aspx )
我没有正确处理CurrentCulture
,或者它应该如何工作? 对于.NET Framework 4.x,我找不到与此问题相关的任何帖子。
我没有正确处理CurrentCulture,或者它应该如何工作?
你不是。 在进入异步操作方法之前 ,需要设置当前UI线程的文化。 如果您在异步方法内部设置文化,它对UI线程没有影响(正如您所发现的那样)。
但是除了异步问题之外,在MVC的应用程序生命周期中 ,在动作方法中设置文化是太迟了,因为MVC的一些重要的文化敏感特性(即模型绑定)在该点之前运行。
在生命周期中尽早设置文化的一种方法是使用授权过滤器,该过滤器确保在模型绑定发生之前设置文化。
using System.Globalization;
using System.Threading;
using System.Web.Mvc;
public class CultureFilter : IAuthorizationFilter
{
private readonly string defaultCulture;
public CultureFilter(string defaultCulture)
{
this.defaultCulture = defaultCulture;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
var values = filterContext.RouteData.Values;
string culture = (string)values["culture"] ?? this.defaultCulture;
CultureInfo ci = new CultureInfo(culture);
Thread.CurrentThread.CurrentCulture = ci;
Thread.CurrentThread.CurrentUICulture = CultureInfo.CreateSpecificCulture(ci.Name);
}
}
并在全球注册:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CultureFilter(defaultCulture: "fi-FI"));
filters.Add(new HandleErrorAttribute());
}
}
上面的示例假定您具有设置路由以将culture
添加为类似于此答案的路由值,但您可以设计过滤器以从其他位置获取文化(如果需要)。
注意:我意识到这个问题不是关于.NET Core,但正如@GSerg在评论中指出的那样, 同样的问题被报告为ASP.NET Core的一个错误,并且它被
by design
关闭by design
。 他们得出的结论是一样的:在资源过滤器中设置区域性将同时应用于操作和视图。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.