Uploading Files with Info Path Form
Hi,
we'd like to provide an Info Path Forms Services based form to give users an easy web based ability to upload new documents with some metada and doeing some plausability tests to check if the metadata do make sense. The form will be presented to external users to provide documents in a structured and qualified way.
So we created the InfoPath form and added a repeating "File-Attachment" control to the form. But with this control the files are attached to the InfoPath form itself and not uploaded to a document library. And so the internal users can not easyly work with the documents.
So what would options do we have to customize InfoPath to provide an possiblility to upload documents to a document library?
Frank
All Replies
- Well, we had the same problem. I think solution for this situation is create .aspx page, wich will contain XmlFormView control with your Infopath form and your .Net user control (for example Upload control) wich will be responcible for uploading logic ....
Hi,
Can you please show me how it is done with the aspx page it will be extremely helpful. Thank you kindly for your help
darryl29
Hello,
Glad to see someone else is trying this as well. What you need to do is add an attribute to the form tag of master page that the aspx page is using. On the master page add this attribute to the form tag:
enctype="multipart/form-data"
More info can be found on Nishand's Blog. http://blogs.gotdotnet.com/nishand/default.aspx
Another approach would be to allow InfoPath to capture the file attachments, then submit the form to a web service that programmatically extracts the files from the form template and posts them to the appropriate document library.
The InfoPath Team Blog has a post with information on how to use the file attachment control:
http://blogs.msdn.com/infopath/archive/2004/03/18/92221.aspx
I've found through experience that storing large attachments within the form XML is pretty slow, but it should be OK for handling an upload as long as you include code to remove the attachment instances from the form XML before you save the XML document - possibly by using a separate element to store the URL of the saved document.
Hi David,
Good point, I should have clarified that this was what I was talking about. However there are two implications. The first is if you are using the XmlFormView control on a page and you need to set the attribute or else there will be an error saying that the file cannot be found. If you check the logs it will say something about pascal session state and that someone is trying to hack your site. The second is that files attached in InfoPath, at least 2007, are encoded in a special format and in base 64. I have combined what I have found. If you can make it better please do and post your suggestions.
Code Snippetusing System;
using System.Collections.Generic;
using System.Text;
using System.IO;
namespace CTED.InfoPath
{
/// <summary>
/// Class used to decode an InfoPath attachment.
/// Pulls the file name and the decoded file from either a base 64 byte array or string.
/// </summary>
public class InfoPathAttachmentDecoder
{
// Private string to hold the attachment name.
string _fileName;
// Private byte array to hold the decoded attachment.
byte[] _decodedFile;
/// <summary>
/// The name of the file within the InfoPath attachment.
/// </summary>
public string Filename
{
get { return _fileName; }
}
/// <summary>
/// The decoded file within the InfoPath attachment.
/// </summary>
public byte[] DecodedFile
{
get { return _decodedFile; }
}
/// <summary>
/// Constructor for the InfoPathAttachmentDecoder Class
/// </summary>
/// <param name="base64EncodedString">The attachment represented by a string</param>
public InfoPathAttachmentDecoder(string base64EncodedString)
{
// Use unicode encoding.
Encoding _encoding = Encoding.Unicode;
// The byte array containing the data.
byte[] _data = Convert.FromBase64String(base64EncodedString);
// Use a memory stream to access the data.
using (MemoryStream _memoryStream = new MemoryStream(_data))
{
// Create a binary reader from the stream.
BinaryReader _theReader = new BinaryReader(_memoryStream);
// Create a byte array to hold the header data.
byte[] _headerData = _theReader.ReadBytes(16);
// Find the file size before finding the file name.
int _fileSize = (int)_theReader.ReadUInt32();
// Get the file name.
int _attachmentNameLength = (int)_theReader.ReadUInt32() * 2;
byte[] _fileNameBytes = _theReader.ReadBytes(_attachmentNameLength);
_fileName = _encoding.GetString(_fileNameBytes, 0, _attachmentNameLength - 2);
// Get the decoded attachment.
_decodedFile = _theReader.ReadBytes(_fileSize);
}
}
/// <summary>
/// Constructor for the InfoPathAttachmentDecoder Class
/// </summary>
/// <param name="base64EncodedBytes">The attachment represented by a byte array</param>
public InfoPathAttachmentDecoder(byte[] base64EncodedBytes) : this(Convert.ToBase64String(base64EncodedBytes)) { }
/// <summary>
/// Static method that gets the file from the attachment.
/// </summary>
/// <param name="base64EncodedString">The attachment represented by a string</param>
/// <returns>Returns a byte array of the file in the attachment.</returns>
public static byte[] DecodeInfoPathAttachment(string base64EncodedString)
{
// Create an instance of the InfoPathAttachmentDecoder
InfoPathAttachmentDecoder _infoPathAttachmentDecoder = new InfoPathAttachmentDecoder(base64EncodedString);
// Return the decoded file.
return _infoPathAttachmentDecoder.DecodedFile;
}
/// <summary>
/// Static method that gets the file from the attachment.
/// </summary>
/// <param name="base64EncodedBytes">The attachment represented by a byte array</param>
/// <returns>Returns a byte array of the file in the attachment.</returns>
public static byte[] DecodeInfoPathAttachment(byte[] base64EncodedBytes)
{
// Create an instance of the InfoPathAttachmentDecoder
InfoPathAttachmentDecoder _infoPathAttachmentDecoder = new InfoPathAttachmentDecoder(base64EncodedBytes);
// Return the decoded file.
return _infoPathAttachmentDecoder.DecodedFile;
}
Here is another option, but can someone explain why it doesn't need to be converted from base64?
Code Snippet/// <summary>
/// Constructor for the InfoPathAttachmentDecoder Class /// </summary> /// <param name="base64EncodedBytes">The attachment represented by a byte array</param> public InfoPathAttachmentDecoder(byte[] base64EncodedBytes){
// 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 = base64EncodedBytes[20] * 2; // Create bytes for the file. byte[] _fnBytes = new byte[_fnLength]; // The actual filename starts at position 24 . . . for (int _index = 0; _index < _fnLength; _index++){
_fnBytes[_index] = base64EncodedBytes[24 + _index];
}
// 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 = System.Text.UnicodeEncoding.Unicode.GetChars(_fnBytes);_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._decodedFile =
new byte[base64EncodedBytes.Length - (24 + _fnLength)]; // Add the bytes to the file. for (int _index = 0; _index < _decodedFile.Length; ++_index){
_decodedFile[_index] = base64EncodedBytes[24 + _fnLength + _index];
}
}
Hi,
I used these class above and saved file name and decode file in database.
Now I have a another infopath form and I 'd like that when it to load I need "SetValue" to File Attachment control.
It`s possible?
I'd like to load this form with a attched file(decode file) in my control!Thanks!Hi,
Is that all the code I need to upload the Attached file 64? I'd be greatly appreaciated if you could give me some instructions in detail.
Thanks in advance.
- Thanks George, your class works perfectly to decode a file from a template, realy helpfull!
Rodolfo Cardoso - can someone give me more detailed instructions to how and where implement this class?


