Multipart Form Data In WCF

Step 1. Create a New WCF Service Project (WCF Service Library)

  1. On the File menu, click New Project.
  2. In the New Project dialog box under Project types, expand Visual C#, click WCF, and select WCF Service Library. In the Name box, type "DemoMultipartWCF". In the Solution name, type "WCFDemo" and then click OK.
  3. Now, delete the default created Interface, Class perspective "IService1.cs" and "Service1.cs".
  4. Add a New Interface by right-clicking on DemoMultipartWCF(project) > Add > New Item and selecting "WCF Service". Name it as "Users. svc", and click ADD.

Step 2. Create an Interface and implement its body.

  1. Create a New Interface in IUsers.cs File (Paste the code, given below)
    [OperationContract]
    [WebInvoke(
        Method = "POST",
        ResponseFormat = WebMessageFormat.Json,
        BodyStyle = WebMessageBodyStyle.WrappedResponse,
        UriTemplate = "UpdateUserDetail"
    )]
    bool UpdateUserDetail(Stream stream);
    
  2. Implement the body of the UpdateUserDetail Interface in Users.svc file (Paste the code, given below)
    public bool UpdateUserDetail(Stream stream)  
    {  
    return false;  
    }  

Step 3. Create a MultipartParser to read the requested form data

Create a New folder named "DataContract" in your project, and add the "CommonDC" class to the folder. Paste the code, given below, in the "CommonDC.cs File" class.

Uses Of All Below Method

  • Parse (Stream stream, Encoding encoding): This method is used to check the input stream in UTF8 (Unicode Transformation Format).
  • ParseParameter (Stream stream, Encoding encoding): This method is used to parse the parameter from the stream
  • IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex): This method is separate from all the requested parameters, which are in the stream.
  • ToByteArray(Stream stream): This method is used to convert the stream to byteArray
    public class MultipartParser
    {
        private byte[] requestData;
        // Require Namespace: using System.IO;
        public MultipartParser(Stream stream)
        {
            // Require Namespace: using System.Text;
            this.Parse(stream, Encoding.UTF8);
            ParseParameter(stream, Encoding.UTF8);
        }
        
        public MultipartParser(Stream stream, Encoding encoding)
        {
            this.Parse(stream, encoding);
        }
        
        private void Parse(Stream stream, Encoding encoding)
        {
            this.Success = false;
            // Read the stream into a byte array
            byte[] data = ToByteArray(stream);
            requestData = data;
            // Copy to a string for header parsing
            string content = encoding.GetString(data);
            // The first line should contain the delimiter
            int delimiterEndIndex = content.IndexOf("\r\n");
            if (delimiterEndIndex > -1)
            {
                string delimiter = content.Substring(0, content.IndexOf("\r\n"));
                // Require Namespace: using System.Text.RegularExpressions;
                // Look for Content-Type
                Regex re = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
                Match contentTypeMatch = re.Match(content);
                // Look for filename
                re = new Regex(@"(?<=filename\=\"")(.* ? )( ?  =  \"")");
                Match filenameMatch = re.Match(content);
                // Did we find the required values?
                if (contentTypeMatch.Success && filenameMatch.Success)
                {
                    // Set properties
                    this.ContentType = contentTypeMatch.Value.Trim();
                    this.Filename = filenameMatch.Value.Trim();
                    // Get the start & end indexes of the file contents
                    int startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;
                    byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
                    int endIndex = IndexOf(data, delimiterBytes, startIndex);
                    int contentLength = endIndex - startIndex;
                    // Extract the file contents from the byte array
                    byte[] fileData = new byte[contentLength];
                    Buffer.BlockCopy(data, startIndex, fileData, 0, contentLength);
                    this.FileContents = fileData;
                    this.Success = true;
                }
            }
        }
        
        private void ParseParameter(Stream stream, Encoding encoding)
        {
            this.Success = false;
            // Read the stream into a byte array
            byte[] data;
            if (requestData.Length == 0)
            {
                data = ToByteArray(stream);
            }
            else
            {
                data = requestData;
            }
            // Copy to a string for header parsing
            string content = encoding.GetString(data);
            // The first line should contain the delimiter
            int delimiterEndIndex = content.IndexOf("\r\n");
            if (delimiterEndIndex > -1)
            {
                string delimiter = content.Substring(0, content.IndexOf("\r\n"));
                string[] splitContents = content.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string t in splitContents)
                {
                    // Look for Content-Type
                    Regex contentTypeRegex = new Regex(@"(?<=Content\-Type:)(.*?)(?=\r\n\r\n)");
                    Match contentTypeMatch = contentTypeRegex.Match(t);
                    // Look for name of parameter
                    Regex re = new Regex(@"(?<=name\=\"")(.*)");
                    Match name = re.Match(t);
                    // Look for filename
                    re = new Regex(@"(?<=filename\=\"")(.* ? )( ?  =  \"")");
                    Match filenameMatch = re.Match(t);
                    // Did we find the required values?
                    if (name.Success || filenameMatch.Success)
                    {
                        // Set properties
                        //this.ContentType = name.Value.Trim();
                        int startIndex;
                        if (filenameMatch.Success)
                        {
                            this.Filename = filenameMatch.Value.Trim();
                        }
                        if (contentTypeMatch.Success)
                        {
                            // Get the start & end indexes of the file contents
                            startIndex = contentTypeMatch.Index + contentTypeMatch.Length + "\r\n\r\n".Length;
                        }
                        else
                        {
                            startIndex = name.Index + name.Length + "\r\n\r\n".Length;
                        }
                        //byte[] delimiterBytes = encoding.GetBytes("\r\n" + delimiter);
                        //int endIndex = IndexOf(data, delimiterBytes, startIndex);
                        //int contentLength = t.Length - startIndex;
                        string propertyData = t.Substring(startIndex - 1, t.Length - startIndex);
                        // Extract the file contents from the byte array
                        //byte[] paramData = new byte[contentLength];
                        //Buffer.BlockCopy(data, startIndex, paramData, 0, contentLength);
                        MyContent myContent = new MyContent();
                        myContent.Data = encoding.GetBytes(propertyData);
                        myContent.StringData = propertyData;
                        myContent.PropertyName = name.Value.Trim().TrimEnd('"');
                        if (MyContents == null) MyContents = new List < MyContent > ();
                        MyContents.Add(myContent);
                        this.Success = true;
                    }
                }
            }
        }
        
        private int IndexOf(byte[] searchWithin, byte[] serachFor, int startIndex)
        {
            int index = 0;
            int startPos = Array.IndexOf(searchWithin, serachFor[0], startIndex);
            if (startPos != -1)
            {
                while ((startPos + index) < searchWithin.Length)
                {
                    if (searchWithin[startPos + index] == serachFor[index])
                    {
                        index++;
                        if (index == serachFor.Length)
                        {
                            return startPos;
                        }
                    }
                    else
                    {
                        startPos = Array.IndexOf < byte > (searchWithin, serachFor[0], startPos + index);
                        if (startPos == -1)
                        {
                            return -1;
                        }
                        index = 0;
                    }
                }
            }
            return -1;
        }
        
        private byte[] ToByteArray(Stream stream)
        {
            byte[] buffer = new byte[32768];
            using(MemoryStream ms = new MemoryStream())
            {
                while (true)
                {
                    int read = stream.Read(buffer, 0, buffer.Length);
                    if (read <= 0) return ms.ToArray();
                    ms.Write(buffer, 0, read);
                }
            }
        }
        
        public List < MyContent > MyContents
        {
            get;
            set;
        }
        
        public bool Success
        {
            get;
            private set;
        }
        
        public string ContentType
        {
            get;
            private set;
        }
        
        public string Filename
        {
            get;
            private set;
        }
        
        public byte[] FileContents
        {
            get;
            private set;
        }
    }
    
    public class MyContent
    {
        public byte[] Data
        {
            get;
            set;
        }
        
        public string PropertyName
        {
            get;
            set;
        }
        
        public string StringData
        {
            get;
            set;
        }
    }
    

Step 4. Implement Pre-Required Method like SaveImageFile & GetEncoder.

Create a Method to save the image file.

public static bool SaveImageFile(byte[] ImageFileContent, string ImagePathWithImageName)  
{  
    try {  
        //Require Namespace: using System.Drawing  
        Image image;  
        //Read Image File  
        using(MemoryStream ms = new MemoryStream(ImageFileContent)) {  
            image = Image.FromStream(ms);  
        }  
        Bitmap bmp = new Bitmap(image);  
        //Require Namespace: System.Drawing.Imaging  
        ImageCodecInfo jgpEncoder = GetEncoder(ImageFormat.Jpeg);  
        //We need to write Encoder with Root otherwise it is an ambiguous between "System.Drawing.Imaging.Encoder" and "System.Text.Encoder"  
        System.Drawing.Imaging.Encoder myEncoder = System.Drawing.Imaging.Encoder.Quality;  
        EncoderParameters myEncoderParameters = new EncoderParameters(1);  
        EncoderParameter myEncoderParameter = new EncoderParameter(myEncoder, 40 L);  
        myEncoderParameters.Param[0] = myEncoderParameter;  
        bmp.Save(ImagePathWithImageName, jgpEncoder, myEncoderParameters);  
        return true;  
    } catch {  
        //Do Code For Log or Handle Exception   
        return false;  
    }  
}  

Note. We need to write Encoder with Root, elsetheret is an ambiguity between "System.Drawing.Imaging.Encoder" and "System.Text.Encoder".

Encoder

Create a method to retrieve the image codecs.

public static ImageCodecInfo GetEncoder(ImageFormat format)  
{  
    ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();  
    foreach(ImageCodecInfo codec in codecs) {  
        if (codec.FormatID == format.Guid) {  
            return codec;  
        }  
    }  
    return null;  
}  

What is the use of ImageCodecInf?

It provides the necessary storage members and methods to retrieve all the pertinent information about the installed image codecs.

Step 5. Implement our interface - UpdateUserDetail

Now, it's time to implement our interface - UpdateUserDetail. (Paste the code, given below)

public bool UpdateUserDetail(Stream stream) {  
    try {  
        //Create an Object of byte[]  
        byte[] buf = new byte[10000000];  
        //Initialise an Object of MultipartParser Class With Requested Stream  
        MultipartParser parser = new MultipartParser(stream);  
        //Check that we have not null value in requested stream  
        if (parser != null && parser.Success) {  
            //Fetch Requested Formdata (content)   
            //(for this example our requested formdata are UserName[String])  
            foreach(var item in parser.MyContents) {  
                    //Check our requested fordata  
                    if (item.PropertyName == "UserName") {  
                        string RequestedName = item.StringData;  
                    }  
                }  
                //Create a GUID for Image Name  
            string ImageName = Guid.NewGuid().ToString();  
            //Image Path  
            string SaveImagePath = "D:/DemoProject/DemoMultipartWCF/DemoMultipartWCF/MyFile/";  
            //Ensure That WE have the right path and Directory  
            if (!Directory.Exists(SaveImagePath)) {  
                //If Directory Not Exists Then Create a Directory  
                Directory.CreateDirectory(SaveImagePath);  
            }  
            //Fetch File Content & Save that Image HERE (for this example our requested FileContent is ProfilePicture[File])  
            string ImagePathWithImageName = SaveImagePath + ImageName + ".bmp";  
            SaveImageFile(parser.FileContents, ImagePathWithImageName);  
            return true;  
        }  
        return false;  
    } catch {  
        //Do Code For Log or Handle Exception   
        return false;  
    }  
}  

Step 6. Ensure the following setting

Now, all is done. Ensure you have the following setting in your Web .config.

<system.serviceModel>  
    <bindings>  
        <basicHttpBinding>  
            <binding maxReceivedMessageSize="999999999" maxBufferSize="999999999" maxBufferPoolSize="9999999999" name="ITransactionProcessor">  
                <readerQuotas maxDepth="32" maxArrayLength="999999999" maxStringContentLength="999999999" />  
                <security mode="TransportWithMessageCredential" /> </binding>  
        </basicHttpBinding>  
    </bindings>  
    <behaviors>  
        <serviceBehaviors>  
            <behavior>  
                <!-- To avoid disclosing metadata information, set the values below to false before deployment -->  
                <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />  
                <!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->  
                <serviceDebug includeExceptionDetailInFaults="true" /> </behavior>  
        </serviceBehaviors>  
        <endpointBehaviors>  
            <behavior name="web">  
                <webHttp helpEnabled="true" /> </behavior>  
        </endpointBehaviors>  
    </behaviors>  
    <protocolMapping>  
        <add binding="basicHttpsBinding" scheme="https" /> </protocolMapping>  
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />  
    <services>  
        <service name="DemoMultipartWCF.Users">  
            <endpoint name="UsersXML" address="" binding="basicHttpBinding" contract="DemoMultipartWCF.IUsers"></endpoint>  
            <endpoint name="UsersJSON" address="json" binding="webHttpBinding" contract="DemoMultipartWCF.IUsers" behaviorConfiguration="web"></endpoint>  
        </service>  
    </services>  
    <client>  
        <endpoint address="https://ics2wstest.ic3.com/commerce/1.x/transactionProcessor" binding="basicHttpBinding" bindingConfiguration="ITransactionProcessor" contract="com.cybersource.api.ITransactionProcessor" name="portXML" /> </client>  
</system.serviceModel>  

Now, it's complementary time.

How to test this WCF Service?

WCF Service

Select POST Method.

POST

Select Body and Fill Form Data. (Requested Data: Username & Requested File: ProfilePicture [browse and select the image]).

Body

Now, just hit Send and here we go.


Similar Articles