Here’s an obscure error I ran into today, and a nasty workaround. In SharePoint 2010, if you add a Library or List to a page, and the view you show has an associated workflow status column, then clicking the link to show the workflow status will result in an error. If you dig in the ULS logs, the error is ‘Index Out of Bounds’. Looking closely at the URL, you can see that the QueryString is not properly formed – it contains an empty List parameter: WrkStat.aspx?List=&WorkflowInstanceId=<guid>
Here’s repro steps:
- Create a new blank site
- Create a new Document library named ‘Test Docs’
- Associate any workflow with the library, set to start when item created
- Edit the blank site’s home page
- Add ‘Test Docs’ as a web part to the page
- Change the view to ‘All Documents’
- Upload a document
- Click the workflow status link
- Observe an error occurs.
- Observe the URL QueryString contains ‘List=&’ (ie a blank List)
The cause of the error is apparently that WrkStat.aspx attempts to use the “List” parameter passed in to the page. (ie, currentWeb.Lists[listId]). This is Bad Design (tm) – your page should be resilient enough to handle junk input in the querystring. Fortunately, that parameter is not strictly required. Removing the List parameter altogether from the querystring results in the page being displayed correctly. Unfortunately, that’s not exactly trivial to do.
When you add a List to a page in SharePoint 2010, behind the scenes you are really adding an XSLTListViewWebPart. This web part can be customized in SharePoint Designer using XSLT. If you’re not familiar with XSLT, you’re very fortunate. It’s a language used to transform XML into something else – in this case HTML to render the list. It’s powerful, but can be a beast to work with. For example, it doesn’t have a built-in “string replace” function, which is just the thing you’ll need to fix up that bum url. Luckily, I found a string replace template online, which gave me what I needed to fix the link.
So, here’s the workaround until this is patched:
- Open the site in sharepoint designer, edit homepage (or, whatever page has the issue)
- place the text cursor in the Workflow Status cell that has the bug
- type ‘test’ – this is to break into custom xslt, and to help you mark where to place the snippets.
- switch to split view
- find the <td></td> that contains some xslt and the word ‘test’. Your cursor _should_ be there already. Replace everything between the <td></td> with Snippet 2.
- Add Snippet 1 to the bottom of the stylesheet, immediately before </xsl:stylesheet>
- Remove the word ‘test’ that you typed, if you didn’t replace it above
- Save
Snippet 1
<xsl:template name="string-replace-all">
<xsl:param name="text" />
<xsl:param name="replace" />
<xsl:param name="by" />
<xsl:choose>
<xsl:when test="contains($text, $replace)">
<xsl:value-of select="substring-before($text,$replace)" disable-output-escaping="yes" />
<xsl:value-of select="$by" disable-output-escaping="yes" />
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text"
select="substring-after($text,$replace)" />
<xsl:with-param name="replace" select="$replace" />
<xsl:with-param name="by" select="$by" />
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$text" disable-output-escaping="yes" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
Snippet 2
<xsl:if test="@ClassInfo='Menu' or @ListItemMenu='TRUE'">
<xsl:attribute name="height">100%</xsl:attribute>
<xsl:attribute name="onmouseover">OnChildItem(this)</xsl:attribute>
</xsl:if>
<xsl:attribute name="class">
<xsl:call-template name="getTDClassValue">
<xsl:with-param name="class" select="$class" />
<xsl:with-param name="Type" select="@Type"/>
<xsl:with-param name="ClassInfo" select="@ClassInfo"/>
</xsl:call-template>
</xsl:attribute>
<xsl:variable name="workflowStatusLink">
<xsl:apply-templates select="." mode="PrintFieldWithECB">
<xsl:with-param name="thisNode" select="$thisNode"/>
</xsl:apply-templates>
</xsl:variable>
<xsl:variable name="workflowStatusLinkFixedUp">
<xsl:call-template name="string-replace-all">
<xsl:with-param name="text" select="$workflowStatusLink" />
<xsl:with-param name="replace" select="'List='" />
<xsl:with-param name="by" select="''" />
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$workflowStatusLinkFixedUp" disable-output-escaping="yes"/>