In a previous post I discussed how to publish InfoPath forms with code behind as a feature in SharePoint 2010. This approached had another side issue to handle; How to save/read the data to/from SP list while you don’t know the URL of the site you’re deploying to. In my case all my InfoPath form were supposed to read from a REST service that I deploy in my feature package. My approach to solve this issue is
- Create a Data Connections Library and deploy it in the feature.
- Create a udcx file that is deployed by default to this library with no URL in the connection Info element.
- Use the code in the event receiver to modify it dynamically based on the deployment URL.
So to get started:
- Add new item, and choose list instance. The Elements.xml should like something like this
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <ListInstance Title="Data Connections Lib" OnQuickLaunch="FALSE" TemplateType="130" FeatureId="00bfea71-dbd7-4f72-b8cb-da7ac0440130" Url="DataConLibrary" Description="Library holding data connections for the feature's forms."> </ListInstance> </Elements> - Now add a new module to the project. Its Elemnts.xml should be like this
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Module Name="DataConnectionsModule" Url="DataConLibrary" RootWebOnly="true"> <File Path="DataConnectionsModuleDataService.udcx" Url="DataService.udcx" Type="GhostableInLibrary"> <Property Name="ContentTypeId" Value="0x010100B4CBD48E029A4AD8B62CB0E41868F2B0" /> <Property Name="_ModerationStatus" Value="0" /> <Property Name="FileLeafRef" Value="DataService.udcx" /> <Property Name="Title" Value="CTS Service" /> <Property Name="Comments" Value="Dynamic udcx deployment example. By Dr. Nader Elshehabi." /> <Property Name="ConnectionType" Value="REST" /> <Property Name="Purpose" Value="ReadOnly" /> <Property Name="ContentType" Value="Universal Data Connection File" /> </File> </Module> </Elements> - The above code essentially tells SharePoint to deploy a file inside the module’s folder called DataService.udcx and fills out its properties -e.g. description, connection type, etc…- and point it to the DataConLibrary we created earlier.
- Now add a new item to the module and choose it to be an XMl file. Rename it to DataService.udcx in the project explorer, then edit it and insert the following code
<?xml version="1.0" encoding="utf-8"?> <udc:DataSource MajorVersion="2" MinorVersion="0" xmlns:udc="http://schemas.microsoft.com/office/infopath/2006/udc"> <udc:Name>Data Service Connection</udc:Name> <udc:Description>Dynamic ucdx example. By Dr. Nader Elshehabi.</udc:Description> <udc:Type MajorVersion="2" MinorVersion="0" Type="Rest"> <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>DataService.svc</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:Authentication><udc:SSO AppId='' CredentialType='' /></udc:Authentication--> </udc:ConnectionInfo> </udc:DataSource> -
Great! Now we almost have everything in order. Now we’ll have a list, and a module that automatically deploys a udcx file to the list and populates its properties. Only one issue, the udcx points to a DataService.svc without specifying its full URL. To achieve this we have to add the following code to the event receiver
using (var site = ((SPSite)properties.Feature.Parent)) { try { //Get the udcx file from the dasta connection library and inject the current site name in it SPQuery query = new SPQuery(); query.ViewXml = @"<Where> <Eq> <FieldRef Name='FileLeafRef' /> <Value Type='Text'>DataService.udcx</Value> </Eq> </Where>"; SPFile udcxFile = site.RootWeb.Lists["Data Connections Lib"].GetItems(query)[0].File; string _tempUDCX = properties.Definition.RootDirectory + "DataService.udcx"; StreamWriter writer = File.CreateText(_tempUDCX); writer.Write(Encoding.Default.GetString(udcxFile.OpenBinary())); writer.Close(); XElement xel = XElement.Load(_tempUDCX); XNamespace udc = "http://schemas.microsoft.com/office/infopath/2006/udc"; xel.Element(udc + "ConnectionInfo").Element(udc + "SelectCommand") .Element(udc + "Query").Value = site.Url + "/_vti_bin/svc/DataService.svc/"; xel.Save(_tempUDCX); StreamReader reader = new StreamReader(_tempUDCX); udcxFile.SaveBinary(Encoding.Default.GetBytes(reader.ReadToEnd())); udcxFile.Update(); reader.Close(); File.Delete(_tempUDCX); //Publishing the data connection file to Central Admin NOT USED NOW //DataConnectionFile x = new DataConnectionFile(); //localFormsService.DataConnectionFiles.Add(_udcxfile, true, true, "CTS EMR"); } catch (Exception ex) { StreamWriter writer = File.CreateText(properties.Definition.RootDirectory + "error.log"); writer.WriteLine("Exception of type {0} was unhandled during activation.", ex.GetType().ToString()); writer.Write(ex.Message); writer.Close(); } } - The above code essentially does the following
- Get the connection file
- Create a temp file and writes the default udcx file to it
- modify the temp file and insert the url of the feature’s parent site -since this features scope is Site the parent is casted as SPSite- into the appropriate location -which is the SelectCommand/ConnectionInfo/Query XMl element-.
- Finally write the temp file back to the original SPFile in the data connections library
And that’s just about it! This way you can deploy multiple udcx files that points only to the names of your lists, and at the time of deployment you can modify the url to be the absolute path to your service -or library or whatever you want to save/read the InfoPath data to/from-. In case you want the udcx file to save you’d have to update the query element inside the UpdateCommand element instead of the SelectElement. There are tons of articles and posts dealing with how to consume data connection files in InfoPath forms so I won’t bother talking about it.
There is an alternative approach and to be honest I don’t remember why I didn’t choose to venture this way as it’s been a long time since I was involved in this project. The alternate approach is to use FormsService.DataConnectionFiles.Add() method to add the data connection to Central Admin like we did with InfoPath forms in the last post. This way in InfoPath you can choose the data connection to be centrally managed.
This is the second shortcut I took in SharePoint. Got any comment, ideas, or even a better way to tackle this issue, I’d really love to hear about it.


Can you please describe the normal steps of deploying an InfoPath form without code in a feature-Receiver?
IĀ used module/feature appraoch and keep getting the error as ” The path is not of a legal form”
There are many posts out there describing the correct way. You’ll have to use a special class called XsnFeatureReceiver that handles everything for you. (http://msdn.microsoft.com/en-us/library/microsoft.office.infopath.server.administration.xsnfeaturereceiver.aspx). Here is a sample post. If you follow it carefully things should work for you. http://sandeepnakarmi.com.np/2011/03/sharepoint-solution-to-deploy-infopath-form-template-as-administrator-approved-form-template/
Hi, this works fine if you deploy the solution as a farm solution. How do I get around with making this work inside the SandBoxed solutions?