Setting the culture settings per request should be easy, right? Well it isn't because you set the culture settings on a thread not a request and apparently ASP.NET doesn't always execute the whole request on a single thread. Sure I could use DefaultThreadCurrentCulture, but that would set the culture on all threads, not just the ones used by the specific request.
So am I missing something here or what? Because when I set the culture in Global.asax's Application_AcquireRequestState()
function (so it executes once at the beginning of each request) for some reason I have property display names popping up in multiple languages and when I dug deeper, I found out that in the Display Name Attribute's constructor the CurrentCulture and CurrentUICulture settings are sometimes completely different from what I set in Global.asax.
I'm sure that the problem isn't in my customized display name attribute, but you can see it below anyway:
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;
}
}
As you can see I even added the LCIDs do the display name so I can see them on the screen, and the Culture Settings are different.
EDIT: I also added timestamps and thread IDs to the debugging output above like this.
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")+")";
It turns out that it persists the DDisplayName attribute instance between requests...huh? Basically, when Html.LabelFor() runs it looks through the metadata for the property to find the display name. When the metadata provider sets the meta data it finds the displayname from the PropertyDescriptor instance which holds a list of attributes for the property. And in this list, the attribute instance for some reason is an old one from a previous request (I know that because of the timestamp I add to the displayname in the constructor). And so, after I switch languages it still uses the old attribute instance that I had when I had set the previous language. So what's happening? Why doesn't it create a new DDisplayName object instance on each request?
EDIT 2: I have no idea why it keeps cashing the attribute instances so I just wrote my own MetaDataProvider that inherits from DataAnnotationsModelMetadataProvider and made sure it finds the real (latest) display name.