Friday, July 30, 2010

Obscure SharePoint 2010 Workflow Status Link Error

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"/>

Saturday, July 10, 2010

How A Microsofty Writes iPad Apps

I’ve just spent a few hours writing my first iPad app, without a Mac, and without Objective-C.  The app itself is nothing special, but the process let me play with a couple new toys.

Sencha Touch is an HTML 5 Application Framework just for developing HTML 5 applications that look and feel like native iPhone, iPad, and Android apps.  It’s based on ExtJS, a jQuery-like JavaScript library, so if you’re familiar with JavaScript and HTML, you can pick this up fairly easily.

WebMatrix was recently announced, and is a great, lightweight website editor that’s perfect for this sort of thing.  I use Visual Studio 2010 for most development I do, but WebMatrix offers a simple, get-out-of-the-way-and-let-me-play UI that’s perfect for hacking away at new code.  At some point, I probably will migrate to Visual Studio – WebMatrix offers a handy ‘Visual Studio’ button for just this occasion.  It ships with IIS Express, a lightweight version of IIS that allows you to quickly serve up folders with many of the bells and whistles of IIS. 

So, with those in hand, I was able to fairly quickly get a proof-of-concept iPad app running. Here’s how to get started yourself:

  • Install the new WebMatrix and IIS Express
  • Download Sencha Touch and copied all of the files into a WebMatrix site.
  • Modify IISExpress’s applicationHost.config to enable off-box requests.
    • Open C:\Users\{YOU}\Documents\IISExpress8\config\applicationHost.config
    • Comment out the binding element for your site
    • Add a new binding element using your machine’s name and a port of your choosing.  Here’s what mine looks like:
            <site name="Empty Site" id="386908880">
                     <application path="/">
                         <virtualDirectory path="/" physicalPath="%IIS_SITES_HOME%\Empty Site" />
                     </application>
                     <bindings>
                         <binding protocol="http" bindingInformation="*:8181:daniellaptop" />
                     </bindings>
                 </site>
  • Modify IISExpress’s applicationHost.config to enable the cache manifest mime type
    • Comment out the .manifest mime type (sorry ClickOnce!)
    • Add the following line: <mimeMap fileExtension=".manifest" mimeType="text/cache-manifest" />
  • Restart WebMatrix, run as admin (This is required if you allow off-box access)
  • Turn off your firewall or open up the port you set above.
  • Add a cache.manifest file to one of the examples
    • Follow the instructions here to build the file
    • Here’s what mine, for the tabs example looks like:
      CACHE MANIFEST
      icon.png
      index.html
      index.js
      phone_startup.png
      tablet_startup.png
      ../../resources/css/ext-touch.css
      ../../ext-touch-debug.js
  • Run the app to get IIS Express cranked up
  • Browse to the site on your iPad
  • Click the  “Plus button” and add to homepage
  • Stop the server or turn off the iPad wifi
  • Run the app from the homepage offline!

That’s it!  I have a few ideas for how I want to put this to use, so stay tuned for some real-world examples.