为每个请求设置文化设置应该很简单,对吧?好吧,它不是因为你在一个线程而不是一个请求上设置文化设置,显然ASP.NET并不总是在一个线程上执行整个请求。当然我可以使用DefaultThreadCurrentCulture,但这会在所有线程上设置文化,而不仅仅是特定请求使用的文化。
我在这里错过了什么或什么?因为当我在Global.asax的Application_AcquireRequestState()
函数中设置文化时(因此它在每个请求的开头执行一次)由于某种原因我有多种语言的属性显示名称,当我深入挖掘时,我发现在显示名称属性的构造函数中,CurrentCulture和CurrentUICulture设置有时与我在Global.asax中设置的完全不同。
我确定问题不在我的自定义显示名称属性中,但您仍然可以在下方看到它:
public class DDisplayName : DisplayNameAttribute
{
public DDisplayName(string resourceId)
: base(GetAttributeName(resourceId))
{ }
private static string GetAttributeName(string resourceId)
{
var lang = System.Threading.Thread.CurrentThread.CurrentCulture.LCID + "|" + System.Threading.Thread.CurrentThread.CurrentUICulture.LCID;
ResourceManager resMan = new ResourceManager(typeof(Strings));
string result = resMan.GetString(resourceId);
return result == null ? "Resource string: " + resourceId + " not found" : result+" "+lang;
}
}
正如你所看到的,我甚至添加了LCIDs的显示名称,以便我可以在屏幕上看到它们,文化设置也不同。
编辑:我还在上面的调试输出中添加了时间戳和线程ID。
var lang = System.Threading.Thread.CurrentThread.CurrentCulture.LCID + "|" + System.Threading.Thread.CurrentThread.CurrentUICulture.LCID;
lang += "(" + System.Threading.Thread.CurrentThread.ManagedThreadId + " | "+DateTime.Now.ToString("HH:mm:ss:fff")+")";
事实证明它在请求之间保留了DDisplayName属性实例......呵呵?基本上,当Html.LabelFor()运行时,它会查看属性的元数据以查找显示名称。当元数据提供者设置元数据时,它从PropertyDescriptor实例中找到显示名称,该实例包含属性的属性列表。在此列表中,属性实例由于某种原因是来自先前请求的旧属性(我知道由于我在构造函数中添加到displayname的时间戳)。因此,在我切换语言之后,它仍然使用我在设置上一语言时所拥有的旧属性实例。那么发生了什么?为什么不在每个请求上创建一个新的DDisplayName对象实例?
编辑2:我不知道为什么它继续兑现属性实例,所以我只编写了自己的MetaDataProvider,它继承自DataAnnotationsModelMetadataProvider,并确保它找到真实的(最新的)显示名称。