El Blanco's Office 2007 Blog

Tuesday, July 11, 2006

InfoPath 2007 File Attachment Control and Browser-Enabled Forms

The InfoPath 2007 File Attachment control can be used to upload documents into an InfoPath form, and works with both InfoPath client and browser-based forms. Dragging a File Attachment control onto the design surface adds a new field into the data source of type "Picture or File Attachment (base64)".

This
link describes the technical details on how this field is formatted.

Basically, there is a header which is of length 24 bytes + length of the filename. Following this head is the file contents. These are base64 encoded.

To work with the uploaded file in .NET code in the InfoPath form you can use code similar to the following (which shows a button handler that copies the uploaded file to a local directory):

public void Button_Clicked(object sender, ClickedEventArgs e)
{
XPathNavigator docXN = this.CreateNavigator();
XPathNavigator opnXN = docXN.SelectSingleNode

("/my:myFields/my:FileAttachment",
this.NamespaceManager);
byte[] attachmentNodeBytes = Convert.FromBase64String
(opnXN.ToString());

// Position 20 contains a DWORD indicating the length of the
// filename buffer. The filename is stored as Unicode so the
// length is multiplied by 2.
int fnLength = attachmentNodeBytes[20] * 2;
byte[] fnBytes = new byte[fnLength];

// The actual filename starts at position 24 . . .

for (int i = 0; i <>
{
fnBytes[i] = attachmentNodeBytes[24 + i];
}

// Convert the filename bytes to a string. The string

// terminates with \0 so the actual filename is the
// original filename minus the last character !
char[] charFileName = UnicodeEncoding.Unicode.GetChars(fnBytes);
string fileName = new string(charFileName);
fileName = fileName.Substring(0, fileName.Length - 1);

// The file is located after the header, which is 24 bytes long

// plus the length of the filename.
byte[] fileContents = new byte[attachmentNodeBytes.Length - (24 + fnLength)];

for (int i = 0; i < fileContents.Length; ++i)
{
fileContents[i] = attachmentNodeBytes[24 + fnLength + i];
}

// We now have an array of bytes (fileContents) which we can
// do what we like with. I'll write them to a temporary file
FileStream fs = new FileStream(@"C:\Temp\InfoPath Test\" + fileName, FileMode.Create);
fs.Write(fileContents, 0, fileContents.Length); fs.Close();
}

Note that since this code is part of the InfoPath 2007 form the InfoPath form will need to have full trust (Tools -> Form Options -> Security and Trusts tab) and hence will need to be Admin deployed to the Microsoft Office SharePoint Server 2007 via Central Administration (don't forget to publish the form to a network location first !).

I'm going to try to incorporate this technique into an InfoPath form used in a custom developed workflow developed using the Sequential SharePoint Workflow template from the Enterprise Content Management Starter Kit, which can be downloaded here.

13 Comments:

  • Nice work... I'm having trouble with an InfoPath form into a SharePoint list and then rollups...

    By Anonymous Anonymous, at 10:21 pm  

  • I’m using InfoPath 2007 beta version display forms using XMLFormView in an ASP.NET page.
    I have a web service to retrieve and submit data to/from the InfoPath form. My web service (stored procedure ultimately) requires a one query field to retrieve data which is Personid. I’m getting it from another ASP.NET page as a parameter which doesn’t have any xmlformview controls in that page .

    I’m using XPathNavigator to select the query field and set the PersonId in the ASP page load event which works fine. I’ve also set a rule in personid field InfoPath template to specify that if it is not blank then automatically query the data base through my web service and get the result which also works fine and I can see all the accurate data in the xmlformview. (call to the stored procedure is visible in SQL profile trace)

    The question is when I modify data and try to submit the form I’m getting a data validation error saying that cant submit the form since some fields are blank. (for example, some fields suppose to contain integers like ‘age’). But in the runtime xmlformview (inside the ASP page) I can see all fields with actual data and they are not blank)

    My assumption is that InfoPath still thinks that fields are blank even though they have been bound to data in the ASP page load event. Cause after getting the ‘cant submit’ error if I refresh the page and manually type a valid person id in the field and retrieve, modify and submit the data it works fine.

    I was using http://msdn2.microsoft.com/en-us/library/ms778201.aspx as a resource and done all steps mentioned there.

    Does anybody faced to this situation before ? Please let me know if you know any articles I can look into too.

    By Blogger chat., at 7:07 pm  

  • InfoJet Service, a product likes InfoPath Forms Services!
    http://www.infojetsoft.com

    By Anonymous David, at 7:54 am  

  • Almost works - wrong slash in your JavaScript segment. text/javascript and not text\javascript.

    Apart from that, Thanks for the post - it was a life-saver!

    By Blogger Scrat, at 2:38 am  

  • great, just what i needed. Thank you

    By Blogger Jani, at 1:34 pm  

  • Great article!! Thanks it has really helped in creating the files in my desired location.

    Just a little note, there is a minor coding error:

    // The actual filename starts at position 24 . . .
    for (int i = 0; i != fnLength; i++)

    By Anonymous Anonymous, at 5:02 am  

  • I CANT get the base64 attachment added when publishing form to my SharePoint server. I guess I need some more detailed explanation. I'd appreaciate your help. Thanks.

    By Anonymous Anonymous, at 3:20 pm  

  • Anonymous - what exact issue are you seeing ? If you give more details I may be able to assist.

    Thanks,
    Chris

    By Blogger Chris White, at 3:42 pm  

  • I have a text box on the form, "FormatName". How can I save files based on above field? If the actual name of the attached file is "abc.txt", how can it be stored as of "xyz.txt" when value of "FormatName" is xyz. Thanks

    By Anonymous Anonymous, at 8:02 pm  

  • Anonymous,

    It's easy to write the file with whatever name you desire - the code in the article details how to get a byte array. Once you have this the article simply writes it to a temporary file, but you can do with it whatever you like !!!

    Hope this helps,

    Chris

    By Blogger Chris White, at 8:11 am  

  • How can I rename the attachment? If attachment is "FileA.doc" how can I rename this attachment it to "FileB.doc" and leave it attached to the form.

    Thank you.

    By Anonymous Anonymous, at 6:32 pm  

  • Hello,

    I've got a question: how to extract attachments from browser-enabled forms to avoid postback from server to client's browser when refresing form after submitting attachment?

    By Anonymous Robert, at 10:02 pm  

  • I just started using InfoPath about a month ago. This tool would be great for a project that I am working on. However, I don't have much programming experience. If it's not too much trouble, can somebody help me implement this code? Will somebody give me, a beginner, step by step instructions to implement the code? thank you--Lawson

    By Blogger Lawson, at 4:49 am  

Post a Comment

<< Home