First of all, I would like to thank Walid Hadjadj to create this part, it was fun working with him on this project.
Ok, so we now know what to look for, soap calls when the InfoPath form is being saved back to the list.
If you want to read up on the formservice.asmx and the entire design, you can download the pdf file here. It’s about the only “complete” information that I could find on the net.
The soap call that we are interested in the most is “SetSchemaChangesForList”. This is the one that is responsible for telling the list to start using the InfoPath aspx pages that we’ve found in the previous blog post.
So first things first:
- I’m re-using my previous solution, so if you don’t have it yet you can get up to speed by just downloading it here.
The extended lookup field, article unit price gave me issues with the redeployment of the InfoPath form, so I’ve removed it.
Also make sure that you download cablib, the file is needed to “extract” and “compress” the InfoPath file on a local storage drive (at the moment it is set to the C:windowsTemp folder, with cleanup functionality)
- Make a reference to the web service “_vti_bin/formsservices.asmx”
- Ok, a forms services helper is included so that the forms are being updated, checked and pushed to the lists (the formshelper.cs will be explained later in the blog)
At the moment all of the information is being pushed via the properties of a feature. Necessary data contains
- Location of the xsn file
- Content Type ID
- List url
only question remains: how are we going to get the InfoPath files in the new site collection …..
The only proper way to do this, is to provision the forms in a solution and deploy them to a document library, from there you can pick them up in code and deploy them to the lists
- So add your InfoPath forms that you’ve downloaded to a directory in the solution and set the type to elements file. Also don’t forget to add the file to the elements.xml, so that the forms are being provisioned to a document library.
either via my admin webpart, where you can just click “download InfoPath forms” or drag them in SharePoint Designer to a document library and download them from there
Ok , so the basics are there, now explaining how we did it.
First of all, there is a lot of logging to the SharePoint logs that I’ve implemented. So if you want to track what all the features are doing, you can use the ULS viewer and see all the lines being added.
- Helpers –> formservices.cs
This is just a default schema that will be used, if you look at the top print screen you can see the newfields tag and the update tag, so this is just a template that is being used later.
We need to instantiate a new forms web service object and bind the object to the current url the forms services asmx file.
The formsServices cannot work cross web, so if the list is listed in the web, you need to reference that web and put the asmx behind the web url.
Next is something very interesting:
Design check form template is a WSDL Operation that checks if your InfoPath form is good or not.
The line above calls a method to get the form template. I’ll come back to this later.
- First we need to retrieve the xsn file from the document library, I’ve passed the url value of the xsn file in the document via the fileUrl attribute.
- Since the InfoPath xsn file is in essence a cabinet file, it can be extracted and compressed by cablib.dll. But we need a location for that, so this is something to watch out for, I’ve chosen the temporary directory in the windows directory on the C drive. In that directory I’m creating a new one that with a random guid number as name. But first I’m checking if that directory already exists or not. This entire method is being run for each InfoPath file so a new directory is created each time with a new guid number of course. And at the end of the method a cleanup is done = deleting the directory.
- Next I’m using extract to extract the xsn file to the temporary folder. Also I’m loading the manifest.xsf in the Xmldocument object to manipulate the xml file.
- Pay very close attention to the “PreserveWhiteSpace = true” line. This is very important. Apparently InfoPath cannot handle the following situation.
- InfoPath will give an error if you want to design it afterwards, because (and I’m not lying) the closing tag of “SubNode” is below the opening tag. The opening/closing of the “Node” tag isn’t a problem, but the “SubNode” tag is. This has taken up a lot of time to find and after a small pair programming session with Milanco (TL at the client) we found the issue. The location of placing the “PreserveWhiteSpace = true” is also from great importance. But it a line lower and it doesn’t do the same thing. You can check here why not .
- Next up I’m going to change the first value and it’s called “baseUrl”, indicating the location of the xsn file in SharePoint structure.
- After setting the value of the “baseUrl” we are going to loop through the nodes looking for a node with the attribute “relativeListUrl”
- when we found the “relativeListUrl” we are getting the SPList object because we need to replace the hardcoded List ID with the new one
- we are also changing the contentTypeID, but I’m not sure if this step is required, because the Content Type ID will remain the same when deploying the CT via the same feature as you deployed to development environment
- After all this the only thing that is left to do is to compress the directory back to an xsn file and return a Base64String back to the first method so that it can run through the Design Checker information object. And cleaning up the 2 directories as well.
- And last, we are pushing the initial value of InfoPath form location, ContentTypeID and relative list url via a feature activation with properties in the feature file
- you call them via the feature receiver and just pass them to the formsservices helper
This may look like an easy task but all of this needed to be investigated and took us almost 2-3 weeks to build. So I hope I’m saving some of you a lot of effort.
Want to learn more?