Developing a InfoPath Solution using a Solution Package


Table of Contents

Source: wss.made4the.net - by Jeremy Thake

  • Site Collection Feature
    • InfoPath Form
      • Automatically to Central Administration Forms Templates
  • Site Feature
    • InfoPath Form Library
      • Provisioned by a Feature
      • Includes the Form Content Type automatically hooked up to it
    • Projects List
      • Provisioned by a Feature
      • List is used within the form in a Drop Down binded by a UDCX Data Connection
    • UDCX Files in a Data Connection Library
  • Provisioned by a Feature
    • Creates a Data Connection Library (DCL) at that Site where Feature activated
    • Creates the UDCX files in the DCL and automatically edits the xml with the correct references to the Projects List in that Site
Webcast available
@jthake has recorded a web cast of this to walk thru the approach:
part 1 Part 1 introduces how to deploy InfoPath forms via Central Administration Administrative Forms
part 2 Part 2 shows how to deploy InfoPath forms via Solution packages in Visual Studio
part 3 Part 3 shows how to use a custom list to store configuration settings for a form to allow the form to be the same for each environment but config settings to sit in the site scope where the form is
part 4 Part 4 actually walks through how to create all the dependencies such as UDCX files in data connection libraries via a Solution Package using SPSource

I used STSDev to create this Solution in Visual Studio to give me the Build Targets quick options for deploying in my development environment.

The benefits to this approach is:

  • No manual deploying of InfoPath Forms in ANY environment
  • The ability to retract the entire thing out as it's a Solution package with Features.
  • Having the whole Solution Package in SOURCE CONTROL
  • UDCX files are automatically generated, no hand coding!
  • UDCX files allow the Feature to be activated at different levels of multiple Site Collections and reference the relative Data Connection Library to point to the relative Projects List without hard coding it directly in the InfoPath Form and having multiple copies for each environment (YUCK!).

The sample code can be found on my Sky Drive.

Sample Code Walk Thru

The solution consists of 2 main elements:

InfoPath Form

InfoPathDeploymentSameple Feature

This feature essentially includes the .xsn file and also a trigger to deploy the Form to Central Administration using these added lines of code in the feature.xml. This is discussed in Sahil Malik's post on how use a solution to deploy the InfoPath Form.

Added to <Feature> element as attributes
 ReceiverClass="Microsoft.Office.InfoPath.Server.Administration.XsnFeatureReceiver"
  ReceiverAssembly="Microsoft.Office.InfoPath.Server, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"

and

Added as a child element of <Feature> element
<Properties>
<Property Key="FeatureName" Value="JeremyThake InfoPath Form Template Sample Feature"/>
</Properties>

InfoPathDependency Feature

This feature includes the two SharePoint Lists used

  • Projects Lists - stores a sample list of projects that InfoPath form uses as a datasource to bind to a drop down list. In the feature receiver there is code to populate the data of the list from the data.xml file in the List Schema Projects folder:
    //Add Projects
            XmlDocument doc2 = new XmlDocument();
            doc2.Load(properties.Definition.RootDirectory + "\\Projects\\data.xml");
            foreach (XmlNode node in doc2.DocumentElement.SelectNodes("//Project"))
            {
                AddProject(web, node.Attributes["Name"].InnerText);
            }
    
  • TestFormLibrary - a test form library for the InfoPath Form to be created from
  • DataConnectionLibrary - this library stores the UDCX file pointing to the projects list which is used by the InfoPath Form. There is no schema required for this list as it is a default ListTemplate, to create it use:
    <ListInstance FeatureId="00BFEA71-DBD7-4F72-B8CB-DA7AC0440130"
      Title="DataConnectionLibrary"
      TemplateType="130"
      Url="Lists/DataConnectionLibrary" />
    

There are two main UDCX stub files attached to this feature.

MainSubmit.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>Main submit</udc:Name>
	<udc:Description>Format: UDC V2; Connection Type: SharePointLibrary; Purpose: WriteOnly; Generated by Microsoft Office InfoPath 2007</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" />
		</udc:UpdateCommand>
		<!--udc:Authentication><udc:SSO AppId='' CredentialType='' /></udc:Authentication-->
	</udc:ConnectionInfo>
</udc:DataSource>
SharePointConnectionTemplate.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>Projects</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>

These two files are used by the FeatureReceiver as templates when creating instances of the UDCX files in the DataConnectionLibrary List.

CreateDataConnectionLibraryListItem(web, "Projects", properties.Definition.RootDirectory, "DataConnectionLibrary");
        CreateDataConnectionLibraryMainSubmitListItem(web, properties.Definition.RootDirectory, "DataConnectionLibrary");

The methods are below:

    /// <summary>
    /// Creates a udcx file based on the template for SharePoint List connections autogenerated by InfoPath 2007
    /// </summary>
    /// <param name="web"></param>
    /// <param name="listName"></param>
    /// <param name="rootDirectory"></param>
    /// <param name="dataConnectionLibraryListName"></param>
    private void CreateDataConnectionLibraryListItem(SPWeb web, string listName, string rootDirectory, string dataConnectionLibraryListName)
    {
        //load template.udcx file
        string templateFileName = rootDirectory + "\\sharepointConnectionTemplate.udcx";

        XmlDocument doc = new XmlDocument();
        doc.Load(templateFileName);
        XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(doc.NameTable);
        nameSpaceManager.AddNamespace("udc", "http://schemas.microsoft.com/office/infopath/2006/udc");

        //replace token with ListID
        Guid listID = web.Lists[listName].ID;
        XmlElement root = doc.DocumentElement;
        XmlNode listIdNode = root.SelectSingleNode("//udc:DataSource//udc:ConnectionInfo//udc:SelectCommand//udc:ListId", nameSpaceManager);
        listIdNode.InnerText = "{" + listID.ToString() + "}";

        XmlNode webUrlNode = root.SelectSingleNode("//udc:DataSource//udc:ConnectionInfo//udc:SelectCommand//udc:WebUrl", nameSpaceManager);
        webUrlNode.InnerText = web.Url.ToString();

        XmlNode descriptionNode = root.SelectSingleNode("//udc:DataSource//udc:Description", nameSpaceManager);
        descriptionNode.InnerText = "Format: UDC V2; Connection Type: SharePointList; Purpose: ReadOnly;";

        UploadToFileToLibrary(web.Lists[dataConnectionLibraryListName], doc, listName + ".udcx");
    }

    /// <summary>
    /// Creates the UserProfileService udcx connection string based on environment
    /// </summary>
    /// <param name="web"></param>
    /// <param name="rootDirectory"></param>
    /// <param name="dataConnectionLibraryListName"></param>
    private void CreateDataConnectionLibraryUserProfileConnectionListItem(SPWeb web, string rootDirectory, string dataConnectionLibraryListName)
    {
        XmlDocument doc = new XmlDocument();
        string connectionFileName = "GetUserProfileByName.udcx";
        doc.Load(rootDirectory + "\\" + connectionFileName);
        XmlNamespaceManager nameSpaceManager = new XmlNamespaceManager(doc.NameTable);
        nameSpaceManager.AddNamespace("udc", "http://schemas.microsoft.com/office/infopath/2006/udc");

        XmlElement root = doc.DocumentElement;

        XmlNode wsdlUrl = root.SelectSingleNode("//udc:DataSource//udc:ConnectionInfo/udc:WsdlUrl", nameSpaceManager);
        wsdlUrl.InnerText = web.Url.ToString() + "/_vti_bin/UserProfileService.asmx?WSDL";

        XmlNode serviceUrl = root.SelectSingleNode("//udc:DataSource//udc:ConnectionInfo//udc:SelectCommand//udc:ServiceUrl", nameSpaceManager);
        serviceUrl.InnerText = web.Url.ToString() + "/_vti_bin/UserProfileService.asmx";

        UploadToFileToLibrary(web.Lists[dataConnectionLibraryListName], doc, connectionFileName);
    }


    private void CreateDataConnectionLibraryMainSubmitListItem(SPWeb web, string rootDirectory, string dataConnectionLibraryListName)
    {
        XmlDocument doc = new XmlDocument();
        string connectionFileName = "MainSubmit.udcx";
        doc.Load(rootDirectory + "\\" + connectionFileName);
        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("//udc:DataSource//udc:ConnectionInfo//udc:UpdateCommand//udc:FolderName", nameSpaceManager);
        folderName.InnerText = web.Url.ToString() + "/Lists/TestFormLibrary/";

        UploadToFileToLibrary(web.Lists[dataConnectionLibraryListName], doc, connectionFileName);
    }

    private void UploadToFileToLibrary(SPList dataConnectionLibrary, XmlDocument doc, string connectionFileName)
    {
        // Convert Xml Document To Byte Array.byte[]
        StringWriter sw = new StringWriter();
        XmlTextWriter xw = new XmlTextWriter(sw);
        doc.WriteTo(xw);
        System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
        byte[] docAsBytes = encoding.GetBytes(sw.ToString());

        //create new list item and upload .udcx file in data connection library
        SPFolder dataConnectionLibraryFolder = dataConnectionLibrary.RootFolder;
        SPFile dataConnectionLibraryFile = dataConnectionLibraryFolder.Files.Add(connectionFileName, docAsBytes);
        //approve SPFile
        dataConnectionLibraryFile.Approve("Approved when feature activated.");
    }

Relative UDCX urls
The UDCX url is relative to the server root (not the site that you are adding the form to e.g.http://server1/DataConnectionLibraryhttp://server2/DataConnectionLibrary

Will work, but if you deploy the solution and activate it at a different level it will not e.g. http://server2/site2/DataConnectionLibrary

If this is an issue, you may want to look at deploying your UDCX files to the Central Administration Data Connection Library instead. The issue here is that if you have multiple sites with different lists, there will be multiple connection files in there pointing to each list.

Labels

solution solution Delete
infopath infopath Delete
udcx udcx Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.


  1. Jun 29, 2009

    Kirk Hofer says:

    Hmmm...did you try this? The Site Columns referenced with the GUIDs do not matc...

    Hmmm...did you try this? The Site Columns referenced with the GUIDs do not match those in the schema.xml. So when deployed, this probably didn't work, or does it work regardless the GUID? Haven't tried it yet myself but thought I would post this. I have been doing too much inside the manifest.xsf

  2. Jul 24, 2009

    Ulrich Strauss says:

    I did this in a similar way. However there is a small issue with updates. If you...

    I did this in a similar way. However there is a small issue with updates. If you upgrade the solution, the upgradesolution will copy the updated infopathform to the feature-directory, however it will not deploy and activate it. Anybody found a way to upgrade those forms?

  3. Aug 19, 2009

    Anonymous says:

    Does this only work for web enabled InfoPath forms or can it also be used for cl...

    Does this only work for web enabled InfoPath forms or can it also be used for client application only forms?

  4. Dec 11, 2009

    Alex Clark says:

    Thanks for posting this Jeremy this was very useful in developing a similar solu...

    Thanks for posting this Jeremy this was very useful in developing a similar solution. The important thing here to remember is that the url is relative to the server root so essentially even if you move servers it will still work (as long as the same data connection library exists in the same location of course).

    In reply to the above - yes this should work fine for client application forms too. In fact when you deploy the InfoPath form as part of a feature to a SharePoint site it will open in the client application by default unless you change the settings.

  5. Dec 22, 2009

    Chad La Fournie says:

    Hi Jeremy, I have been trying to replicate your process as per the above as wel...

    Hi Jeremy,

    I have been trying to replicate your process as per the above as well as the web casts. However, I have run into an issue that I suspect does relate to guids as per the comment above. Assuming that this did work could you provide the code? Note that I did download the code posted on your skydrive but it appears somewhat out of date. The error I am getting (both in my implementation and in deploying the wsp from your sample code) is that the udcx file is "not from a data connection library."

    Thanks in advance for any help you can offer.

    Chad La Fournie

    1. Dec 23, 2009

      Jeremy Thake says:

      I would recommend creating a Data Connection Library and then using SPSource to ...

      I would recommend creating a Data Connection Library and then using SPSource to reverse engineer into a list_elements.xml file to provision this. In the web casts I go through this.

      1. Dec 23, 2009

        Chad La Fournie says:

        Thanks for the reply. That was actually the method I was following. I did end u...

        Thanks for the reply. That was actually the method I was following.

        I did end up resolving the issue. The lists_manifest.xml file generated by spsource had arbitrary values (10000) for the template type. After manually changing the types to 130 in both the ListTemplate and the ListInstance the error message no longer appears and things appear to be working correctly.

  6. Mar 01

    Kostadin Markov says:

    Hi, good article! My question is - must I use Visual Studio 2010, or I can ...

    Hi, good article!

    My question is - must I use Visual Studio 2010, or I can stay with 2008 to reimplement the funcionality from the webcasts?!

    1. Mar 01

      Jeremy Thake says:

      This tutorial is for VS2008. In general, the majority of tutorials you will find...

      This tutorial is for VS2008. In general, the majority of tutorials you will find on SharePoint 2007 will be on VS2008. VS2010 will be for any SharePoint 2010 relevant stuff.

      1. Mar 01

        Kostadin Markov says:

        Ok, I made a shot, but I rechecked and there is VS2010 in the last tur...

        Ok, I made a shot, but I rechecked and there is VS2010 in the last turorial - http://www.screencast.com/t/NTE2NzFj . I will watch thoroughly all the four to make things clear!

        1. Mar 01

          Jeremy Thake says:

          Yes apologies, things are slightly different in the UI between VS2008 and VS2010...

          Yes apologies, things are slightly different in the UI between VS2008 and VS2010. But the code etc shown above will work in VS2008 also.

  7. Mar 03

    Forms Builder says:

    Good information here. Really helped me out!

    Good information here. Really helped me out!


Creative Commons License
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. Hosted generously by CustomWare