This week I was not only busy with migrating old portals and solving problems but I was also busy with creating a console application that does the following :
- Extract the attachments from a submitted InfoPath form and uploading those into a document library and return the links from the documents
Ofcourse this requirement is so generic that I had to be out there on our beloved world wide web ;) And luckily.. it was.. partly..! I found the following pieces of invaluable information: Upload an InfoPath attachment to a document library by Koen Roos and KB892730: How to encode and decode a file attachment programmatically by using Visual C# in InfoPath.
First things first.. what is Koen talking about in his post? Well he references another post that describes how you can generates classes out of your XML file. Since all submitted InfoPath forms are purely XML you can generate classes from it as well! So how does it work then?
- Download a copy of a submitted form to your development machine
- Run the Visual Studio Command line
- Execute the following cmd : XSD "name of the submitted form"
- Execute the following cmd : XSD "name of the created XSD file" /CLASSES
- Open Visual Studio and open up your workflow project (see previous posts about how-to-do this)
- Add the just created .cs file to your project
- Then you can use code to get access to the values from the infopath fields in an OO way
System.Xml.Serialization.XmlSerializer xSerializer = new System.Xml.Serialization.XmlSerializer(typeof(myFields)); myFields res = (myFields)xSerializer.Deserialize(str);
Where MyFields is the main datasource in my InfoPath form, so now when I want to access a particular field within my datasource I can use "res.AttachmentField" or "res.FirstName" to get the values. Now to get the binary data from the attached files I used the code from the KB article that can encode and decode the string and that will look like this :
InfoPathAttachmentDecoder dec = new InfoPathAttachmentDecoder(r.AttachmentField);
Now to put that back into a document library as a document we do the following
SPFolder AttachmentStore = web.GetFolder("Document Library"); AttachmentStore.Files.Add(dec.Filename, dec.DecodedAttachment);
To put it al together it will look like (so you can copy/paste it more conveniently ;))
SPSite site = new SPSite("http://portal/sites/subsite"); SPWeb web = site.OpenWeb(); SPFile file = web.GetFile(@"http://portal/sites/subsite/Document Library/form.xml"); System.IO.StreamReader str = new System.IO.StreamReader(file.OpenBinaryStream()); System.Xml.Serialization.XmlSerializer xSerializer = new System.Xml.Serialization.XmlSerializer(typeof(myFields)); myFields res = (myFields)xSerializer.Deserialize(str); InfoPathAttachmentDecoder dec = new InfoPathAttachmentDecoder(res.AttachmentField); SPFolder AttachmentStore = web.GetFolder("Document Library"); AttachmentStore.Files.Add(dec.Filename, dec.DecodedAttachment);
Now the next step is to make a custom workflow activity using this code.. but I will save that for another post ;)