我有一个在 IIS 8 中的网站下运行的 ASP.NET MVC 5 WEB 应用程序,我需要在运行时通过从数据库读取并存储在会话变量中的用户首选项以编程方式更改语言,并且此值可以在运行时更改带有下拉菜单。
问题是语言资源有时不会改变,尽管 CurrentCulture 确实如此,更糟糕的是它们在应用程序级别冻结,使得所有其他用户会话也冻结到该语言,并且只会在所有应用程序会话中显示相同的语言无论他们的偏好,或者他们甚至试图在运行时更改他们的语言,这都会卡住,这在正常工作时会强制 CurrentThread.CurrentCulture 进行更改。
我在视图中使用隐藏文本来跟踪 CurrentThread.CurrentCulture 是什么以及正在按预期变化,所以问题一定出在其他地方。
这是我用来检查 CurrentCulture 的剃须刀块
<div style="display:none; visibility: hidden;">Thread
@System.Threading.Thread.CurrentThread.CurrentCulture</div>
在运行时,当语言或 resx 被冻结/卡在应用程序级别时,该值确实是正确的并被选中,但它与视图中显示的语言不匹配,并且在我进行例如更改之前它不会正常工作web.config 或重新启动应用程序,然后它可以正常工作一段时间,但不要持续太长时间。
<div style="display:none; visibility: hidden;">Thread en-US</div>
问题是,这发生在所有用户会话的应用程序级别,并且 CurrentCulture 实际上在应用程序正常工作时按预期发生变化,并且无论何时重新启动,这种情况都不会发生,但不知何故,每次用户会话期间都会触发某些事情以冻结所有当前会话甚至新会话的语言。
我也尝试将文化逻辑的更改放在剃须刀视图、动作过滤器和基本控制器中,但这并没有解决问题,以前我有一个基本控制器,我的所有控制器都继承了它,并且 Global.asax.cs 的逻辑要更改并确定文化。
我目前的方法是删除基本控制器并在 Global.asax.cs Application_AcquireRequestState (我也尝试过使用 Application_BeginRequest 但不知何故在生命周期中太早)和操作过滤器中使用。
这是在 Global.asax.cs
protected void Application_AcquireRequestState(object sender, EventArgs e)
{
if (Context.Session != null && Context.Session["CultureName"] != null)
{
string cultureName = Context.Session["CultureName"].ToString();
CultureInfo cultureInfo = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}
我的动作过滤器是这样的
public class CultureActionAttribute : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
string cultureName = null;
string tenant = filterContext.RouteData.Values["Tenant"] as string;
if (!String.IsNullOrWhiteSpace(tenant))
{
TenantService tenantService = new TenantService(tenant);
cultureName = CultureHelper.GetImplementedCulture(tenantService.Tenant.LanguageCulture);
tenantService.Unit.Dispose();
}
//Logic to override cultureName value by getting the user preference language
CultureInfo cultureInfo = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentCulture = cultureInfo;
Thread.CurrentThread.CurrentUICulture = cultureInfo;
}
}
我在 FilterConfig 中添加了它
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new CultureActionAttribute());
//
}
我什至尝试在用户更改文化时使用 ClearCachedData。
Thread.CurrentThread.CurrentCulture.ClearCachedData();
我认为这可能与缓存或池回收有关,但我不知道下一步该尝试什么。
我没有在 web.config 中使用任何全球化标签。
在 CurrentThread.CurrentCulture 的视图中跟踪的值始终是正确的,错误的是资源使用冻结。
资源与将它们放置在单独的专用标准文件夹中并使用 PublicResXFileCodeGenerator 将它们公开以能够编译并可供控制器、视图等访问的做法是一致的
资源文件夹
任何人都可以为我提供另一种选择来尝试或思考我可能做错了什么,或者我还能尝试使资源始终如一地工作。