ContentType Workflows not being updated in the Site Collection

 

This is a problem we've been seeing for a long time in our development and production server.  It is hard to describe the error, but there are a series of consequences.

  • We have reusable content type workflows defined for a InfoPath Form content type.
  • The Workflow Association is created at the root content type level and pushed down through the site collection, for every Forms Library that uses the content type.
  • Sometimes, we discover that an older version of the workflow is running, after we've updated the workflow. 
  • Next, we'll find that for some reason, for one specific Forms Library, the Workflow Association is still pointing to the old workflow template, so even when we manually start a new instance of a workflow, it is still running the older version.
  • In our specific case, the error was happening with Nintex Workflows, but this is not a Nintex Workflow problem - the problem is in the underlying SharePoint platform and how it is creating the workflow associations.

 

The Chase

 

I begin to write scripts to try to catch the form libraries that has this behaviour.  I worked out how to read the Workflow Association records.  For every workflow association, there is an InternalName field that looks like this:

  • [workflow name] <Cfg.{guid}>

When it is updated, the current workflow association is renamed to:

  • [workflow name (Previoius Version:{date}) <Cfg.{guid}>

Additionally, each Workflow Association has a BaseId that points to a BaseTemplate object, and the Template object has an Indexer Property

  • template["DeclarativeConfiguration"] - which gives back the same Cfg.{guid}

So a program (or script) can be written that looks through all the form libraries in our site collection, and report on content type workflow associations where the Cfg.{guid} on the Workflow Association doesn't match the one on the template.

 

UpdateAssociationToLatestVersion

 

Each Workflow Associations collection has a special method that will attempt to update the Workflow Associations to the latest version.  The method UpdateAssociationToLatestVersion will detect the Cfg difference, create a new Association to the latest template, rename the old Workflow Association to Previous, and set the old WorkFlow Association to continue running, but not start new instances.

 

The Error

 

I see a few scenarios.  When there is a workflow instance currently running, that seems to be when the Workflow Association for that Form Library breaks.

I also begin to watch SharePoint's Workflow Association table and notice that when a Workflow Association is broken, it seems to have a strange StatusFieldName "ows_" - this is for the Workflow Status column, but shouldn't be with that specific name.

image

 

Deep into the logs, I also see this exception buried:

Column 'ows_' does not exist. It may have been deleted by another user.

 

The Fix

 

Some quick search turns up Stefan Gossner's blog post from 2011.  Which describes the problem probably better than I could.  Essentially, when you have a lot of Lookup in your List View (remembering that each Workflow Status column is actually also a Lookup), it is possible for your List View Lookup Threshold throttling to break the code that creates new Workflow Associations.  When this exception happens, the existing Workflow Association is broken and must be manually removed and recreated.  And in the broken state, it will not Update to the latest version.

http://blogs.technet.com/b/stefan_gossner/archive/2011/05/20/error-message-quot-column-ows-does-not-exist-quot-when-updating-workflow-associations-on-a-list.aspx

image

 

The Aftermath

 

After we bumped the List View Lookup Threshold from 8 to 50, we are now able to update our Workflow Templates, and the correct Workflow Associations are being created and pushed down.  We still have a bunch of broken associations that requires attention and fixing, but at least we can identify them and correct them manually.

Very, very annoying problem, but it feels good to finally find the solution that has plagued us for months.

Modifying CSS Styles based on InfoPath field without code

This is an article expanding on a comment I made previously on the Microsoft InfoPath forums.

http://social.msdn.microsoft.com/Forums/en-US/sharepointcustomizationprevious/thread/4a8dbae1-4641-4ee2-b034-3768ebda5a47

The Problem

How do we modify the margin of a column based on a field within InfoPath. 

 

Solution

Invoking dark magics of XSL (you have read the disclaimer).  This is totally unsupported, but fun.

  1. Create a new form, add a number field "n1".
  2. Put this field onto the design area within a section
  3. Create a rule on the section, "if n1 > 0", make the background red.
    (these steps are useful to set up the form to a stage where we can add additional rules).
  4. save your form as "MarginForm.xsn", we're about to do unsupported magic. 
  5. go to File | Publish | Export | Export Source Files - save the component files of your form into a blank folder, e.g. "C:\Temp\MarginForm\"
  6. close InfoPath designer, go to your folder, and look for the XSL file for your view, typically, it's <view name>.xsl.  For me, this is: C:\Temp\MarginForm\view1.xsl
  7. Open the xsl in a text editor - preferably one that understands XSL to give you syntax highlighting.
  8. Find our formatting rule, it looks like this:
    <xsl:attribute name="style">BORDER-BOTTOM: 0pt; BORDER-LEFT: 0pt; WIDTH: 100%; MARGIN-BOTTOM: 0px; BORDER-TOP: 0pt; BORDER-RIGHT: 0pt;<xsl:choose>
    <xsl:when test="../my:n1 &gt; 0">BACKGROUND-COLOR: #ff6600; caption: Rule 1;</xsl:when>
    </xsl:choose>
    </xsl:attribute>
  9. add additional formatting for margin-left, like this:
    <xsl:attribute name="style">BORDER-BOTTOM: 0pt; BORDER-LEFT: 0pt; WIDTH: 100%; MARGIN-BOTTOM: 0px; BORDER-TOP: 0pt; BORDER-RIGHT: 0pt;<xsl:choose>
    <xsl:when test="../my:n1 &gt; 0">BACKGROUND-COLOR: #ff6600; caption: Rule 1; MARGIN-LEFT: <xsl:value-of select="../my:n1"/>px;</xsl:when>
    </xsl:choose>
    </xsl:attribute>
  10. save your XSL, close it.  Open  the whole thing back in InfoPath designer from manifest.xsf
  11. test it and save it back into MarginForm.xsn file.
  12. Once you are comfortable and understand what's going on, clean up the rule in xsl (don't use the designer) and get rid of the rule for "red".

The Results

 

Download Files

 

A site maintenance notice.  I've removed all back references on the site - they were being spammed like crazy and I wasn't doing a good job of cleaning them up.  If you need a back reference, please leave a comment and I'll verify them.

Windows 8 - Export Google Reader OPML for Bing News

Let the hacks begin!

Windows 8's Bing News app was updated in the last few days and with this new version, an ability was added to allow us to add our own Sources.  RSS sources.

A number of my favourite news sites proceed to discuss this is a good direction to eventually be a viable Google Reader replacement.

http://winsupersite.com/windows-8/windows-8-tip-add-rss-feeds-news-app

http://www.liveside.net/2013/04/15/bing-news-app-a-google-reader-replacement-not-yet-but-its-a-start/

 

My lament is that it doesn't seem to accept OPML, a common XML-based description of my RSS feed collection.

 

Inspiration

Hmm, I wonder how does Bing News store the RSS feeds that a user has chosen.

 

Hack

Windows Apps data are stored within the user's App data.  In my case, it is right here.

C:\Users\John.Liu\AppData\Local\Packages\Microsoft.BingNews_8wekyb3d8bbwe\

Having a quick look around, the custom Source feeds are stored in

\RoamingState\state.json

JSON format is a simple javascript format.  So really, the hack is not even a hack, just converting OPML (XML) to JSON.

A powershell script, like this opml-to-bing-news-json.ps1, could do it.

 

Steps

 

  1. Download your Google Reader files from Google TakeOut.
    image
  2. Open the ZIP file and copy the subcriptions.xml file to the same folder as the Powershell script
  3. My region market is "en-au" - check your state.json file to see if you have a different market.  Change it in your powershell script ps1.

    Run it like so...

    image
  4. You should have these files now:
    image

  5. Overwrite the state.json file in AppData with mine...
    image
  6. Restart Bing News

    image
  7. Bonus.  When I launch my Surface RT, all my feeds are already synchronized there too :-)

Retrospective - Australian SharePoint Conference Sydney 2013

I had planned to post this as soon as I finish my session - but you know, conference.  Lots of friends come visit during these events and the evenings do a lot of damage to your hair, and possibly liver.  I don't often get opportunities to chat with so many SharePoint experts in such a short span of time.  Lots of catch up, lots of thoughts, A LOT of ideas.

 

As for my session, Building SharePoint Solutions with Microsoft's TypeScript: how and why.  I think it went well.  I really wanted to thank the audience for being so kind, and stayed awake through the presentation.  As promised, here is my presentation:

Presentation:

 

Downloads:

A huge thanks to the organisers, speakers, vendors and attendees for such a fantastic conference.  I hope to see you guys again soon.

InfoPath - reading template.xsd in code for type checking

InfoPath is the world's most advanced XML-based form system.  Each InfoPath document is a fully structured XML file, and the template contains the XSD schema definition for the XML file.  This includes a bunch of information such as min/max occurrences, as well as the type information for each of the elements.

Because the information for the element's type is stored separately in the xsd file, it isn't possible at runtime to workout what the type of each element is supposed to be. 
When we are given:

  • my:value1

If we can't read the template.xsd file, we don't know if that's a number, a string, a datetime nor do we know if the field is nillable.  Some fields in InfoPath, such as the boolean and the datetime fields, can't be blank.  They have to be set to nil.

 

Here's how you can read the template.xsd in code

An InfoPath Form

 

Here is an InfoPath form with a few fields

image

 

The XML File Connection

 

Add a XML File Data Connection to an existing file in the template, I use "template.xml"

image

Save the template, and now drop into the code behind.

 

Code

public void InternalStartup()
{
    EventManager.FormEvents.Loading += new LoadingEventHandler(FormEvents_Loading);
}

public void FormEvents_Loading(object sender, LoadingEventArgs e)
{
    FileQueryConnection file = this.DataConnections["template"] as FileQueryConnection;
    file.FileLocation = "template.xsd";
    file.Execute();
    XPathNavigator template = this.DataSources["template"].CreateNavigator();
    string notes = "";

    foreach (XPathNavigator nav in this.CreateNavigator().Select("//*", this.NamespaceManager))
    {
        string localname = nav.LocalName;

        XPathNavigator element = template.SelectSingleNode("//*[@name='" + localname + "']", template);
        if (element != null)
        {
            notes += string.Format("{0} is of type {1} {2}; ", localname, element.GetAttribute("type", ""), element.GetAttribute("nillable", ""));
        }
    }

    this.CreateNavigator().SelectSingleNode("/my:myFields/my:notes", this.NamespaceManager).SetValue(notes);
}

  • The interesting part is at the top, where we bait and switch the FileQueryConnection to read the template.xsd schema file instead.  Because it is a valid XML file, InfoPath will read it happily.
  • We can then map any field in the main datasource to the corresponding definition in the template, and pull out the additional metadata such as type or nillable.

 

Result

image

 

Download