Thursday, March 3, 2011

How to deploy a .UDCX file to a Data Connection Library using correct ListId

I'll try to give workaround on one of the most common problems related with InfoPath deployment. Probably everybody who had deployed InfoPath forms before knows about it.


The Problem: deploying InfoPath Forms to production
Once development is done, we need to move the form template from development to production. The problem is that we don't know the ListId in advance. According Universal Data Connection v2.0 Reference and Schema in MSDN the .UDCX file has the following structure:


<?MicrosoftWindowsSharePointServices ContentTypeID=”0x010100B4CBD48E029A4ad8B62CB0E41868F2B0”?>
<udc:DataSource MajorVersion="2" MinorVersion="0" xmlns:udc="http://schemas.microsoft.com/office/infopath/2006/udc">
    <udc:Name>Main submit</udc:Name>
    <udc:Description>Format: UDC V2; Connection Type: SharePointLibrary; 
Purpose: WriteOnly; Generated by Microsoft Office InfoPath 2007 on 2010-07-13 at 16:04:26 by 
DEV\svc_mossfarm_vm0150.</udc:Description>
    <udc:Type MajorVersion="2" MinorVersion="0" Type="SharePointLibrary">
        <udc:SubType MajorVersion="0" MinorVersion="0" Type=""/>
    </udc:Type>
    <udc:ConnectionInfo Purpose="WriteOnly" AltDataSource="">
        <udc:WsdlUrl/>
        <udc:SelectCommand>
            <udc:ListId/>
            <udc:WebUrl/>
            <udc:ConnectionString/>
            <udc:ServiceUrl UseFormsServiceProxy="false"/>
            <udc:SoapAction/>
            <udc:Query/>
        </udc:SelectCommand>
        <udc:UpdateCommand>
            <udc:ServiceUrl UseFormsServiceProxy="false"/>
            <udc:SoapAction/>
            <udc:Submit/>
            <udc:FileName>Specify a filename or formula</udc:FileName>
            <udc:FolderName AllowOverwrite="1">/Lists/SubmittedFormsLib/</udc:FolderName>
        </udc:UpdateCommand>
        <!--udc:Authentication><udc:SSO AppId='' CredentialType='' /></udc:Authentication-->
    </udc:ConnectionInfo>
</udc:DataSource>
 

Let's focus on  the ConnectionInfo Element and especially on the SelectCommand Element


Most common practice is to generate this .UDCX file with InfoPath using the Convert button on the Data Sources form. Once converted the ListId element is hard coded with the GUID of a list... cool, uh? That makes the .UDCX file absolutely useless when we need to deploy it to some other server.


Suggested solution
I read numerous articles describing that specifying a list by name in an .UDCX file instead of the ListId works fine, but actually I never managed to make it work.
Even I tried with the name of the list, the internal name of the List, relative path of the list, absolute path.... it never get working. I was still receiving an error when I open the InfoPath form.

So finally I stop trying to find a working "hack". In my vision putting ListName when it is explicitly specified in MSDN that the .UDCX file expect ListId is either bug in SharePoint or "hack"

My workaround
As replacing ListId with Name doesn't work for me I created new feature that basically read all of the files in the Data Connection Library and manually update the relevant List IDs

First of all we need these steps:
  • Create new feature that deploy the InfoPath Forms
  • Create new feature that deploy the InfoPath Data Connection Files (.UDCX)
  • Create new feature that update uploaded .UDCX files
  • Add EventReceiver to our InfoPathDataConnectionUpdate feature
  • Add Feature Activation Dependency (we need InfoPathDataConnection feature to be activated before InfoPathDataConnectionUpdate)
And here is that we have in our InfoPathDataConnectionUpdate.EventReceiver.cs


First let's define 2 constants that we need. Infopath Data Connections library is standard out of the box library, so we search for it by name (no need to use GUID in this case)





And here is our method UpdateDataConnectionLibrary that actually get the connection file and simply update the xml node that contains the ListId. Have in mind that in my solution the names of the Lists are exactly the same as the names of the .UDCX files:


So for all of these .UDCX files I have coresponding lists/libraries that are names exactly the same way:
ApplicationsUsed
Criticality
Effectiveness
....

This way in the event receiver simply use the item.DisplayName in the foreach
foreach (SPListItem item in web.Lists[InfopathDataConnections].Items)
{
       //Main Submit udcx is used for submit only. No need to update ListID
       if (item.DisplayName == "Main Submit") continue;
   
      UpdateDataConnectionLibrary(web, item.File, item.DisplayName);
}

Otherwise you should create your own mapping that map the .udcx file with the corresponding SharePoint list. Anyway best practice is to have exactly the same list name as the data connection file

You can download the event receiver from here

3 comments:

Anonymous said...

nice job! Thanks for sharing. I used this today and it definitely saved me a lot of time.

Anonymous said...

I keep on getting the following error on connectionfile.OpenBinaryStream()

ReadTimeout: 'connectionfile.OpenBinaryStream().ReadTimeout' threw an exception of type 'System.InvalidOperationException'
WriteTimeout: 'connectionfile.OpenBinaryStream().WriteTimeout' threw an exception of type 'System.InvalidOperationException'


Any help would be great.

SharePoint Masters said...

Most likely the file is not found. Can you debug and check what is the name of the file you are trying to open