Second Life of a Hungarian SharePoint Geek

May 29, 2016

Content Query Web Part Issue on SharePoint 2013 Developer Site – Just another Workaround

Filed under: Bugs, CQWP, SP 2013 — Tags: , , — Peter Holpar @ 05:42

Yesterday I was to test the Content Query Web Part (CQWP), but when wanted to edit its settings, I got an error that was logged in ULS like:

Application error when access /Pages/YourPage.aspx, Error=Key cannot be null.  Parameter name: key   at System.Collections.SortedList.IndexOfKey(Object key)     at System.Collections.SortedList.ContainsKey(Object key)     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.AppendListTypes(SortedList sortedListItems, SPListTemplateCollection listTypes)     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.populateListTypeDropDown()     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.populateCBQControls()     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.OnPreRender(EventArgs e)     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System…
….Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
System.ArgumentNullException: Key cannot be null.  Parameter name: key    at System.Collections.SortedList.IndexOfKey(Object key)     at System.Collections.SortedList.ContainsKey(Object key)     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.AppendListTypes(SortedList sortedListItems, SPListTemplateCollection listTypes)     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.populateListTypeDropDown()     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.populateCBQControls()     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.OnPreRender(EventArgs e)     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecur…
…siveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
Getting Error Message for Exception System.Web.HttpUnhandledException (0x80004005): Exception of type ‘System.Web.HttpUnhandledException’ was thrown. —> System.ArgumentNullException: Key cannot be null.  Parameter name: key     at System.Collections.SortedList.IndexOfKey(Object key)     at System.Collections.SortedList.ContainsKey(Object key)     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.AppendListTypes(SortedList sortedListItems, SPListTemplateCollection listTypes)     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.populateListTypeDropDown()     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.populateCBQControls()     at Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart.OnPreRender(EventArgs e)    …
… at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Control.PreRenderRecursiveInternal()     at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)     at System.Web.UI.Page.HandleError(Exception e)     at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)     at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesA…
…fterAsyncPoint)     at System.Web.UI.Page.ProcessRequest()     at System.Web.UI.Page.ProcessRequest(HttpContext context)     at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()     at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

As it turned out by the analyzing the source code of the methods in the stack trace, the error is caused by the AppendListTypes method (Microsoft.SharePoint.Publishing.WebControls.ContentByQueryToolPart class in Microsoft.SharePoint.Publishing assembly). This method iterates through the available list templates in the web site just to add their name to a list box of the tool part. The ContainsKey method of the System.Collections.SortedList class is used to check, if the given name already exists in the list, for the case multiple list templates would have the same name. In this case a numeric counter would be appended to the name to avoid name conflicts in the list. So far so good.

But if the Name property of the list template happens to be null, calling the ContainsKey method with this value as key causes an ArgumentNullException. It is the IndexOfKey method of the SortedList class that throws the exception, just to be exact.

We can find out which list templates have null as their Name via this script:

$web = Get-SPWeb http://YourSite
$web.ListTemplates | ? { $_.Name -eq $null }

This script returns in our case a single list template with InternalNameDraftAppsListTemplate”. The type property of the template is SPListTemplateType.DeveloperSiteDraftApps, that means the integer value 1230 (decimal) or 0x4ce (hexadecimal).

Just as remark: there is another template without name, but in this case the name is not null, but it is an empty string, so it does not cause problem for the CQWP tool part. This list template has the internal name “wfsvc”. Its list template type is not included in the SPListTemplateType enumeration, the integer value of the type is 4501. This list template serves as a base for a list instance that is used by SharePoint to keep track of workflows.

My first idea was to set the Name property of the “DraftAppsListTemplate” template via a script like this:

$lt = $web.ListTemplates | ? { $_.Name -eq $null }
$lt.Name = ‘DraftAppsListTemplate’
$lt.Update()

Of course it fails, due to the read-only behavior of the Name property and due the lack of the Update method on the SPListTemplate class.

As a second try, I searched for possible solutions on the web, and found this forum thread, where it is suggested as a workaround to temporary inactivate the feature the list template belongs to while one wants to edit the CQWP properties:

Disable-SPFeature -Identity e374875e-06b6-11e0-b0fa-57f5dfd72085 -Url http://YourSite

I don’t like this idea, as:

– there might be cases that somebody without the permission to activate / inactivate features should edit the CQWP

– inactivating the feature affects the site functionality and may disrupt of work other using the same environment

So instead of that I came up with another workaround. Of course, it is not a fully supported solution so you should use it only for your own risk.

I’ve created a backup copy of the file containing the list template (located at 15\TEMPLATE\FEATURES\Developer\DeveloperListTemplates.xml), and edited the original version, adding the missing DisplayName attribute to the XML definition of the list template.

Note: The DisplayName attribute corresponds to the Name property of the SPListTemplate class, while the Name attribute translates to the InnerName property.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"&gt;
  <ListTemplate
      FeatureId="E374875E-06B6-11E0-B0FA-57F5DFD72085"
      BaseType="0"
      Name="DraftAppsListTemplate"
      DisplayName="DraftAppsListTemplate"
      DisableAttachments="TRUE"
      DisallowContentTypes="TRUE"
      FolderCreation="FALSE"
      Hidden="TRUE"
      HiddenList="False"
      OnQuickLaunch="False"
      SecurityBits="11"
      Type="1230"
      VersioningEnabled="FALSE"
      AllowDeletion="FALSE" >
  </ListTemplate>
</Elements>

I saved the changes and performed an IISRESET. After that I had no more list templates with null as Name, and was able to edit the CQWP properties without inactivating any features.

The real solution would be to fix the error in the AppendListTypes method.

First of all, one should avoid possible null values. Instead of the current code:

string name = template.Name;

it would be better:

string name = (template.Name != null) ? template.Name : template.InnerName;

I assume the Name attribute of the ListTemplate schema, that corresponds the InnerName property of the SPListTemplate class is a mandatory one, as described here. So the new expression could not be evaluated to null any more. Although at the same place the DisplayName attribute that corresponds to the Name property of the SPListTemplate class is defined as required either, its lack of the original version of the DeveloperListTemplates.xml file demonstrates, it is not mandatory in practice. If we want to be sure we can append this line to the former one:

name = name ?? string.Empty;

Second, I don’t see if there is really any possible business case, when one would include items from lists created based on the DraftAppsListTemplate in the CQWP. So one should simply skip this list template at all in the modified version of the AppendListTypes method:

switch (type)
{
    case 110:
    case 0x76:
    case 0x75:
    case 0x2776:
    case 600:
    case 1230:
        break;

    default:
    {
       // code block is omitted intentionally
    }
}

Our farm is patched with Cumulative Update, May 2016, might be that Microsoft provides a fix in a later update.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: