Lately I've been putting together a solution that involves some InfoPath forms. I love InfoPath for what it is, but let's face it, it can be a bit painful. One of the biggest pain points is that it's not easily deployable. This is mostly due to the udcx having a reference to the guid of the list they were created on.
I've read a few articles saying that you can simply change the guid to the list name. This didn't work for me so I've come up with a different way to do it which I thought I'd share.
Essentially I'm using 3 features, the first one to deploy the Data connection list instance and the list that the UDCX will connect to, the second to deploy all of the udcx's I'll need, and then the third loops through them and updates the guid and the web URL.
Let's look at it in details. I'm using WSPBuilder (downloadable from codeplex.com) and suggest others do as well.
The first step is to create a new project. Open up Visual Studio create a WSPBuilder Project
Next we need to create our first feature for the List Instances.
Right click your solution and select Add, New Item
Then Select WSPBuilder, Blank Feature, make sure you give it a name then click OK
Scope your feature to Web, and un-tick Event Handler Click finish
The following goes in the elements.xml
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<ListInstance
FeatureId = "00BFEA71-DBD7-4F72-B8CB-DA7AC0440130"
Hidden = "False"
OnQuickLaunch = "False"
RootWebOnly = "TRUE"
TemplateType = "130"
Title = "Data
Connections"
Url = "DataConnections"
Description="Library to store Data
Connections"
VersioningEnabled = "FALSE"/>
</Elements>
Note: The above will add a Data Connections Library,
you can also add other list instances to this feature for example the list or
library the UDCX will connect to.
So that's step One, we have a data connections library to hold the UDCX's.
Step Two, we need some UDCX's
Create another feature –using the same steps as above, scope it at a web
level, again un-tick Event Handler.
Once it's created, right click your new feature folder and select Add, New
Item
Create a new XML file. This File MUST have the same name as the library that
it will be connected to and the extension needs to be .udcx (see image below for
example)
The following goes in the .udcx
<?xml version="1.0" encoding="UTF-8"?>
<?MicrosoftWindowsSharePointServices ContentTypeID="0x010100B4CBD48E029A4ad8B62CB0E41868F2B0"?>
<udc:DataSource MajorVersion="2" MinorVersion="0" xmlns:udc="http://schemas.microsoft.com/office/infopath/2006/udc">
<udc:Name>UDCX Display
Name</udc:Name>
<udc:Description/>
<udc:Type MajorVersion="2" MinorVersion="0" Type="SharePointList">
<udc:SubType MajorVersion="0" MinorVersion="0" Type=""/>
</udc:Type>
<udc:ConnectionInfo Purpose="ReadOnly" 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=""/>
</udc:UpdateCommand>
</udc:ConnectionInfo>
</udc:DataSource>
Basically, it's an emply UDCX. You can change the display name and the
description. Go ahead and create as many empty UDCX files that you need.
Remember they need to be named ListDisplayName.udcx
Next we need to tell the feature to deploy them to the data connection
library.
This is done with a module. The following goes into the Elements file of the
UDCX feature
<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<Module Name="DataConnections" Url="DataConnections" Path="">
<File Url="LibraryDisplayName.udcx"
Type="GhostableInLibrary" IgnoreIfAlreadyExists="FALSE">
<Property Name="Title" Value="Library Display Name.udcx"></Property>
</File>
</Module>
</Elements>
Add a File element for each of the UDCXs that you need to deploy.
OK, we now have a populated Data Connection Library. We now need to update
those empty UDCX's with the right information.
Create another feature – using the same method as above, this time scope it
to Web and leave the Event Handler ticked. WSPBuilder will automatically create
a feature Receiver for this feature, and tell feature to use it. In the feature
receiver add the following code
(be sure to update your
namespace and class to match your feature!)
using System;
using System.Collections.Generic;
using System.Xml;
using System.Text;
using System.Globalization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
namespace
InfopathDataConnections.EventHandlers.Features
{
public class UpdateUDCXReceiver : SPFeatureReceiver
{
const string
DataConnectionsLibrary = "Data Connections";
const string
ListIdXPath = "/udc:DataSource/udc:ConnectionInfo/udc:SelectCommand/udc:ListId";
const string
weburlXPath = "/udc:DataSource/udc:ConnectionInfo/udc:SelectCommand/udc:WebUrl";
public override
void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
foreach (SPListItem item in web.Lists[DataConnectionsLibrary].Items)
{
if (item.DisplayName != "Main Submit")
{
UpdateDataConnectionLibrary(item);
}
}
}
private void
UpdateDataConnectionLibrary(SPListItem item)
{
XmlDocument doc = new XmlDocument();
using (System.IO.Stream stream = item.File.OpenBinaryStream())
{
doc.Load(stream);
}
XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(doc.NameTable);
nameSpaceManager.AddNamespace("udc", "http://schemas.microsoft.com/office/infopath/2006/udc");
XmlElement root = doc.DocumentElement;
XmlNode folderName =
root.SelectSingleNode(ListIdXPath, nameSpaceManager);
SPList locationsList =
item.Web.Lists[item.DisplayName]; //
GetList(item.Web.Url + "/Lists/" + item.DisplayName);
folderName.InnerText =
locationsList.ID.ToString("b");
XmlNode weburlfolder =
root.SelectSingleNode(weburlXPath, nameSpaceManager);
weburlfolder.InnerText =
item.Web.Url.ToString();
System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
item.File.SaveBinary(encoding.GetBytes(doc.InnerXml));
item.File.Approve("Guid and WebUrl Added");
}
}
}
The above code firstly checks to make sure the ucx is not a Main Submit as we
don't want to try to change those. It them looks for a List or Library on the
current site with the same name as the udcx file and grabs the guid and puts it
and the current web into the relevant areas of the udcx. It then approves the
udcx so it is usable.
NOTE: you may need to change the target framework to
.NET 3.5 - to do this, go to project Properties (right click your project)
select the applications tab, change the Target Framework to .NET Framework 3.5
(rebuild if required)
That's it, it should all work. If you'd like to see an example, there is one
over on my Downloads page or click
here.
J