OutOfRangeException in SharePoint 2013 SetThreadCulture method

The problem

Recently I had to work on a tricky SharePoint bug. Sometimes users called about a correlation ID that was displayed when accessing a SharePoint publishing site. The issue was sporadic. In some cases refreshing the page was enough but on other cases the correlation ID was displayed during several minutes. We were running SharePoint Server 2013 with SP1 without any cumulative updates.

So we did what any SharePoint developer would have done : scanning the ULS logs. Here is a copy of the exception :

System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.Collections.Generic.Dictionary2.FindEntry(TKey key)
at System.Collections.Generic.Dictionary
2.TryGetValue(TKey key, TValue& value)
at Microsoft.SharePoint.SPFallback1.GetPath(T node)
at Microsoft.SharePoint.SPFallback
1.GetPathLength(T startNode, T endNode, Int32& length)
at Microsoft.SharePoint.SPFallback`1.TryDetermineBestMatch(T[] supporteds, T[] desireds, IsMatched isMatched, LanguageDecisionOptions options, T& bestMatch)
at Microsoft.SharePoint.SPLanguageSettings.TryDetermineLanguage(UInt32[] supportedLcids, UInt32[] desiredLcids, LanguageDecisionOptions options, UInt32& bestMatchedLcid)
at Microsoft.SharePoint.SPLanguageSettings.TryDetermineLanguage(String[] supportedLanguages, String[] desiredLanguages, LanguageDecisionOptions options, String& language)
at Microsoft.SharePoint.WebPartPages.Utility.ComputeUICultureForMUIWebs(String strMUILanguages, UInt32 WebLanguage, UInt32& uiCultureLcid)
at Microsoft.SharePoint.WebPartPages.Utility.SetThreadCulture(SPWeb spWeb, Boolean force)
at Microsoft.SharePoint.ApplicationRuntime.SPRequestModuleData.GetFileForRequest(HttpContext context, SPWeb web, Boolean exclusion, String virtualPath)
at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.InitContextWeb(HttpContext context, SPWeb web)
at Microsoft.SharePoint.WebControls.SPControl.SPWebEnsureSPControl(HttpContext context)
at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.GetContextWeb(HttpContext context)
at Microsoft.SharePoint.ApplicationRuntime.SPRequestModule.PostResolveRequestCacheHandler(Object oSender, EventArgs ea)
at System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

Note : text in bold was found in several locations in ULS. Text that is not in bold is variable since the “SetThreadCulture” method is called by many other methods. So you can encounter the same behavior with a different stack trace.

Why? (Skip if you are not a developer)

The problem happens when SharePoint sets the thread culture. We have french language pack installed on our Farm and the SharePoint site on which the error occurs is multilingual. Moreover we  developed a custom product to translate our publishing pages. This tool is setting the thread culture depending of the current user’s language preference. Since we have some custom code that is playing with the thread culture we thought that was a good lead. Unfortunately our code seemed OK and we didn’t find any problem with it.

At this time we decided to decompile the Microsoft.SharePoint.dll assembly and search for any clue.

Here is the code of the “GetPath” method you can see in the stack trace :

The m_path field that is highlighted is instantiated in the constructor the generic SPFallback class :

And the SPFallback instance used by SPLanguageSettings (check the stack trace if you are lost) is actually static (I invite you to decompile the SPLanguageSettings class if you are curious). To summarize the m_path Dictionary is shared by all the requests made on this particular Web Application…

Did you see that coming?

A lot of .Net developers are not aware that a Dictionary is not thread-safe in .Net. Worst : you can end with a high cpu usage when reading and writing in a Dictionary concurrently!

A Dictionary<TKey, TValue> can support multiple readers concurrently, as long as the collection is not modified. Even so, enumerating through a collection is intrinsically not a thread-safe procedure (MSDN).

See the thread safety section of the Dictionary reference : https://msdn.microsoft.com/en-us/library/xfhwa508(v=vs.110).aspx

The funny thing is that the developer who wrote this piece of code was aware of a potential concurrent issue so he (or she) decided to put a lock (Monitor.Enter actually) around the block that clears the m_path Dictionary. Unfortunately that is not enough!

The solution

Install the May 2014 Cumulative Update! In the description you can read :

When you change the fallback language on a SharePoint Server 2013 server, you experience high CPU usage on the server.

Here is the link : https://support.microsoft.com/en-us/kb/2878240

If you are a developer and you are curious about how this has been fixed, you can decompile the code after applying the CU and you will see that the Dictionary I was talking about has been replaced by a ConcurrentDictionary.

SharePoint Image Renditions Size Restriction

Image Renditions are a great feature of SharePoint 2013. While writing another blog post about Image Renditions I figured out that there is actually a maximum size when adding an Image Rendition.

If you are used to add Image Renditions by using the UI you may have noticed the validation message “The value entered is invalid. Value must be a number between 1 and 2048” :

If you are a developer like me who is playing with the API before the OOB features this limit is not so obvious. When you are provisioning Image Renditions thanks to a SharePoint Feature you won’t have any messages or log entries to warn you. The Image Renditions with a width or height over 2048 will be simply ignored.

Is it possible to configure your environment to increase this value? No. When decompiling the IsValid method of the Microsoft.SharePoint.Publishing.ImageRendition class you can notice that 2048 is actually a constant.

It’s not really an issue in my opinion. You probably won’t need to generate renditions over this size but I think it’s good to know this limitation when deploying this kind of artifacts for SharePoint.

Custom WebPart ToolPart with SharePoint look and feel

Sometimes things that should be pretty simple are finally a lot more complicated than you would imagine. Today I tried to create a custom WebPart ToolPart to expose a custom property. Writing a toolpart for a SharePoint WebPart is pretty straightforward. You need to create a class that inherits Microsoft.SharePoint.WebPartPages.ToolPart. This class will handle the controls needed to edit your custom properties. Then you have to override the GetToolParts method to return the SharePoint base ToolParts and yours.

I won’t explain here in detail the steps needed to create the ToolPart, if you need more info you can read the post of Tobias Zimmergren here : http://zimmergren.net/technical/how-to-custom-web-part-properties-toolpart

So after putting these blocks together you end up with this :

That’s was not what I was expected at all ! See the difference with the Advanced section that is OOB. Instead of the collapsible panel with the blue title I get an ugly ASP .Net style toolpart.

So I decided to run one of my favorite SharePoint developer tool : dotPeek (I’m saying dotPeek is a SharePoint tool because when you start developing serious solutions for SharePoint there is a point you just NEED to explore the API by yourself).

After decompiling a couple of classes I finally found the control that is used to render the toolpart like SharePoint does.

Here are the steps to recreate the look and feel of a SharePoint ToolPart :

  1. Disable the Chrome of the ToolPart in the constructor.
  2. Instantiate a Panel Control into CreateChildControls. You have to put an id to this panel, it is required by the JavaScript which is handling the collapse / expand functionality.
  3. Instantiate a Microsoft.SharePoint.WebPartPages.TPPanel with reflection (this is an Internal type) and pass the Panel created in step 2 in the argument list.
Here is a code sample of the CreateChildControls method :

Warning : we are using reflection here to instantiate a control that is marked as internal. You shouldn’t use this method because it’s not supported by Microsoft. I won’t argue on this topic in this post but personally I’m OK with that. The only risk is to break the functionality when upgrading to the next version of SharePoint, unfortunately if I try to reproduce the SharePoint style by applying the same CSS than the TPPanel on custom controls I probably have to change the CSS with the next version. You know what? I rather prefer to update a line of C# every 3 years than struggling with some CSS.

That being said here is the result :

If you want to apply the SharePoint style on the Controls inside the TPPanel I invite you to download the attached project that contains a full example of Custom ToolPart. The final result :

I hope you will enjoy your custom toolpart with SharePoint Look and Feel ! Don’t hesitate to leave a comment if you have any question.

CustomToolPane.zip (13KB)

CustomToolPane-1.zip (updated version VS2015)