diff --git a/src/Umbraco.Core/ThreadExtensions.cs b/src/Umbraco.Core/ThreadExtensions.cs new file mode 100644 index 0000000000..68f6959e91 --- /dev/null +++ b/src/Umbraco.Core/ThreadExtensions.cs @@ -0,0 +1,51 @@ +using System.Globalization; +using System.Threading; + +namespace Umbraco.Core +{ + static class ThreadExtensions + { + public static void SanitizeThreadCulture(this Thread thread) + { + // get the current culture + var currentCulture = CultureInfo.CurrentCulture; + + // at the top of any culture should be the invariant culture - find it + // doing an .Equals comparison ensure that we *will* find it and not loop + // endlessly + var invariantCulture = currentCulture; + while (invariantCulture.Equals(CultureInfo.InvariantCulture) == false) + invariantCulture = invariantCulture.Parent; + + // now that invariant culture should be the same object as CultureInfo.InvariantCulture + // yet for some reasons, sometimes it is not - and this breaks anything that loops on + // culture.Parent until a reference equality to CultureInfo.InvariantCulture. See, for + // example, the following code in PerformanceCounterLib.IsCustomCategory: + // + // CultureInfo culture = CultureInfo.CurrentCulture; + // while (culture != CultureInfo.InvariantCulture) + // { + // library = GetPerformanceCounterLib(machine, culture); + // if (library.IsCustomCategory(category)) + // return true; + // culture = culture.Parent; + // } + // + // The reference comparisons never succeeds, hence the loop never ends, and the + // application hangs. + // + // granted, that comparison should probably be a .Equals comparison, but who knows + // how many times the framework assumes that it can do a reference comparison? So, + // better fix the cultures. + + if (ReferenceEquals(invariantCulture, CultureInfo.InvariantCulture)) + return; + + // if we do not have equality, fix cultures by replacing them with a culture with + // the same name, but obtained here and now, with a proper invariant top culture + + thread.CurrentCulture = CultureInfo.GetCultureInfo(thread.CurrentCulture.Name); + thread.CurrentUICulture = CultureInfo.GetCultureInfo(thread.CurrentUICulture.Name); + } + } +}