Thursday, 12 July 2012

Insert file attachment control in infopath form and submit that form in form library

 









Design This form using infopath from

1.Open infopath form

2.In  top menu bar u can see controls in tat choose under objects->choose File attachment control

3 .Add 3 buttons named attach,submit and close.

For attachment field we have to write coding otherwise we cannot add attachment field as fields value.

We have to encode and decode and write code for attach & submit button to save attached documents in document library
In infopath form under developer->code editor->visual studio will open->in this create class file.cs as attachment encoding and paste the below coding

 Encoder .cs coding

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace name
{
    class InfoPathAttachmentEncoder
    {
        private string base64EncodedFile = string.Empty;
        private string fullyQualifiedFileName;

        /// <summary>
        /// Creates an encoder to create an InfoPath attachment string.
        /// </summary>
        /// <param name="fullyQualifiedFileName"></param>
        public InfoPathAttachmentEncoder(string fullyQualifiedFileName)
        {
            if (fullyQualifiedFileName == string.Empty)
                throw new ArgumentException("Must specify file name", "fullyQualifiedFileName");

            if (!File.Exists(fullyQualifiedFileName))
                throw new FileNotFoundException("File does not exist: " + fullyQualifiedFileName, fullyQualifiedFileName);

            this.fullyQualifiedFileName = fullyQualifiedFileName;
        }

        /// <summary>
        /// Returns a Base64 encoded string.
        /// </summary>
        /// <returns>String</returns>
        public string ToBase64String()
        {
            if (base64EncodedFile != string.Empty)
                return base64EncodedFile;

            // This memory stream will hold the InfoPath file attachment buffer before Base64 encoding.
            MemoryStream ms = new MemoryStream();

            // Obtain the file information.
            using (BinaryReader br = new BinaryReader(File.Open(fullyQualifiedFileName, FileMode.Open, FileAccess.Read, FileShare.Read)))
            {
                string fileName = Path.GetFileName(fullyQualifiedFileName);

                uint fileNameLength = (uint)fileName.Length + 1;

                byte[] fileNameBytes = Encoding.Unicode.GetBytes(fileName);

                using (BinaryWriter bw = new BinaryWriter(ms))
                {
                    // Write the InfoPath attachment signature.
                    bw.Write(new byte[] { 0xC7, 0x49, 0x46, 0x41 });

                    // Write the default header information.
                    bw.Write((uint)0x14);    // size
                    bw.Write((uint)0x01);    // version
                    bw.Write((uint)0x00);    // reserved

                    // Write the file size.
                    bw.Write((uint)br.BaseStream.Length);

                    // Write the size of the file name.
                    bw.Write((uint)fileNameLength);

                    // Write the file name (Unicode encoded).
                    bw.Write(fileNameBytes);

                    // Write the file name terminator. This is two nulls in Unicode.
                    bw.Write(new byte[] { 0, 0 });

                    // Iterate through the file reading data and writing it to the outbuffer.
                    byte[] data = new byte[64 * 1024];
                    int bytesRead = 1;

                    while (bytesRead > 0)
                    {
                        bytesRead = br.Read(data, 0, data.Length);
                        bw.Write(data, 0, bytesRead);
                    }
                }
            }


            // This memorystream will hold the Base64 encoded InfoPath attachment.
            MemoryStream msOut = new MemoryStream();

            using (BinaryReader br = new BinaryReader(new MemoryStream(ms.ToArray())))
            {
                // Create a Base64 transform to do the encoding.
                ToBase64Transform tf = new ToBase64Transform();

                byte[] data = new byte[tf.InputBlockSize];
                byte[] outData = new byte[tf.OutputBlockSize];

                int bytesRead = 1;

                while (bytesRead > 0)
                {
                    bytesRead = br.Read(data, 0, data.Length);

                    if (bytesRead == data.Length)
                        tf.TransformBlock(data, 0, bytesRead, outData, 0);
                    else
                        outData = tf.TransformFinalBlock(data, 0, bytesRead);

                    msOut.Write(outData, 0, outData.Length);
                }
            }

            msOut.Close();

            return base64EncodedFile = Encoding.ASCII.GetString(msOut.ToArray());
        }
    }
}

Decoder .cs coding

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;

namespace name
{
    class InfoPathAttachmentDecoder
    {
        private const int SP1Header_Size = 20;
        private const int FIXED_HEADER = 16;

        private int fileSize;
        private int attachmentNameLength;
        private string attachmentName;
        private byte[] decodedAttachment;

        /// <summary>
        /// Accepts the Base64 encoded string
        /// that is the attachment.
        /// </summary>
        public InfoPathAttachmentDecoder(string theBase64EncodedString)
        {
            byte[] theData = Convert.FromBase64String(theBase64EncodedString);
            using (MemoryStream ms = new MemoryStream(theData))
            {
                BinaryReader theReader = new BinaryReader(ms);
                DecodeAttachment(theReader);
            }
        }

        private void DecodeAttachment(BinaryReader theReader)
        {
            //Position the reader to obtain the file size.
            byte[] headerData = new byte[FIXED_HEADER];
            headerData = theReader.ReadBytes(headerData.Length);

            fileSize = (int)theReader.ReadUInt32();
            attachmentNameLength = (int)theReader.ReadUInt32() * 2;

            byte[] fileNameBytes = theReader.ReadBytes(attachmentNameLength);
            //InfoPath uses UTF8 encoding.
            Encoding enc = Encoding.Unicode;
            attachmentName = enc.GetString(fileNameBytes, 0, attachmentNameLength - 2);
            decodedAttachment = theReader.ReadBytes(fileSize);
        }

        public void SaveAttachment(string saveLocation)
        {
            string fullFileName = saveLocation;
            if (!fullFileName.EndsWith(Path.DirectorySeparatorChar.ToString()))
            {
                fullFileName += Path.DirectorySeparatorChar;
            }

            fullFileName += attachmentName;

            if (File.Exists(fullFileName))
                File.Delete(fullFileName);

            FileStream fs = new FileStream(fullFileName, FileMode.CreateNew);
            BinaryWriter bw = new BinaryWriter(fs);
            bw.Write(decodedAttachment);

            bw.Close();
            fs.Close();
        }

        public string Filename
        {
            get { return attachmentName; }
        }

        public byte[] DecodedAttachment
        {
            get { return decodedAttachment; }
        }
    }
}

Attach and submit button code

using Microsoft.Office.InfoPath;
using System;
using System.Xml;
using System.Xml.XPath;
using Microsoft.SharePoint;

namespace name
{
    public partial class FormCode
    {
        // Member variables are not supported in browser-enabled forms.
        // Instead, write and read these values from the FormState
        // dictionary using code such as the following:
        //
        // private object _memberVariable
        // {
        //     get
        //     {
        //         return FormState["_memberVariable"];
        //     }
        //     set
        //     {
        //         FormState["_memberVariable"] = value;
        //     }
        // }

        // NOTE: The following procedure is required by Microsoft InfoPath.
        // It can be modified using Microsoft InfoPath.
        public void InternalStartup()
        {
            ((ButtonEvent)EventManager.ControlEvents["btnAttach"]).Clicked += new ClickedEventHandler(btnAttach_Clicked);
            ((ButtonEvent)EventManager.ControlEvents["btnSave"]).Clicked += new ClickedEventHandler(btnSave_Clicked);

            //((ButtonEvent)EventManager.ControlEvents["CTRL5_5"]).Clicked += new ClickedEventHandler(CTRL5_5_Clicked);
            ((ButtonEvent)EventManager.ControlEvents["CTRL11_5"]).Clicked += new ClickedEventHandler(CTRL11_5_Clicked);
        }
//Attach Field code        

public void btnAttach_Clicked(object sender, ClickedEventArgs e)
        {
            //Create an XmlNamespaceManager
            XmlNamespaceManager ns = this.NamespaceManager;

            //Create an XPathNavigator object for the Main data source
            XPathNavigator xnMain = this.MainDataSource.CreateNavigator();

            //Create an XPathNavigator object for the attachment node
            XPathNavigator xnAttNode = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentField", ns);

            //Create an XPathNavigator object for the filename node
            XPathNavigator xnFileName = xnMain.SelectSingleNode("/my:myFields/my:theAttachmentName", ns);

            //Obtain the text of the filename node.
            string fileName = xnFileName.Value;
            if (fileName.Length > 0)
            {
                //Encode the file and assign it to the attachment node.
                InfoPathAttachmentEncoder myEncoder = new InfoPathAttachmentEncoder(fileName);

                //Check for the "xsi:nil" attribute on the file attachment node and remove it
                //before setting the value to attach the filerRemove the "nil" attribute
                if (xnAttNode.MoveToAttribute("nil", "http://www.w3.org/2001/XMLSchema-instance"))
                    xnAttNode.DeleteSelf();

                //Attach the file
                xnAttNode.SetValue(myEncoder.ToBase64String());
            }
        }

        //public void CTRL5_5_Clicked(object sender, ClickedEventArgs e)
//save button code
        public void btnSave_Clicked(object sender, ClickedEventArgs e)
        {
            // Retrieve the value of the attachment in the InfoPath form
            XPathNavigator ipFormNav = MainDataSource.CreateNavigator();
            XPathNavigator nodeNav = ipFormNav.SelectSingleNode(
            "/my:myFields/my:theAttachmentField", NamespaceManager);

            string attachmentValue = string.Empty;

            if (nodeNav != null && !String.IsNullOrEmpty(nodeNav.Value))
            {
                attachmentValue = nodeNav.Value;

                // Decode the InfoPath file attachment
                InfoPathAttachmentDecoder dec =
                new InfoPathAttachmentDecoder(attachmentValue);
                string fileName = dec.Filename;
                byte[] data = dec.DecodedAttachment;

                // Add the file to a document library

               // using (SPSite site = new SPSite("site collection name"))
                using(SPSite site = SPContext.Current.Site)
                {

                    using (SPWeb web = site.OpenWeb())
                    {
                        web.AllowUnsafeUpdates = true;
                        SPFolder docLib = web.Folders["library name];
                        docLib.Files.Add(fileName, data);
                        web.AllowUnsafeUpdates = false;
                        web.Close();
                    }
                    site.Close();
                }

            }

        }


Then save and publish.








1 comment:

  1. Thanks for sharing the complete source code to insert a file attachment control. I have been trying to implement the same but is not fully aware of all these controls and functions. I will make use of the above code.
    infopath signing

    ReplyDelete