Techbubbles

WCF Service using MTOM in .NET FW 4

 

Web services having a greater interoperability to communicate messages across heterogeneous systems, however challenge is serializing the data into XML. Users may want to send images,videos, drawings, xml documents etc. together with SOAP message. 

What is MTOM?

Message Transmission Optimization Mechanism (MTOM) is a mechanism of transferring transferring large amounts binary data as an attachment to SOAP message.

Typical SOAP message transmission shown in the below image

MTOM Process

Image Source crosscheknet.com


WSE 3.0 supports Message Transmission Optimization Mechanism for transmitting large amounts of data to and from web services in earlier .NET FW versions now it is obsolete. We can write WCF service to use MTOM. In this post I am going to discuss uploading a file using WCF MTOM service and compares the payload of the message between text encoding and MTOM encoding.

1. Open the Visual Studio 2010 and create a WCF service

image 

2. The service contract in the project looks as follows

 

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Runtime.Serialization;

   5: using System.ServiceModel;

   6: using System.ServiceModel.Web;

   7: using System.Text;

   8: using System.IO;

   9:  

  10: namespace MTOMWcfService

  11: {

  12:     //Service Contract UploadFile Service

  13:     [ServiceContract(Namespace="MTOMWcfService")]

  14:     public interface IService

  15:     {

  16:         [OperationContract]

  17:         byte[] UploadFile(Stream fileStream);

  18:    }

  19: }

3. The service Implementation class as below. Upload File method saves the supplied stream disk.

   1: using System;

   2: using System.Collections.Generic;

   3: using System.Linq;

   4: using System.Runtime.Serialization;

   5: using System.ServiceModel;

   6: using System.ServiceModel.Web;

   7: using System.Text;

   8: using System.IO;

   9:  

  10: namespace MTOMWcfService

  11: {

  12:     public class MTOMService : IService

  13:     {

  14:  

  15:         public byte[] UploadFile(Stream fileStream)

  16:         {

17: IncomingWebRequestContext context =

WebOperationContext.Current.IncomingRequest;

  18:             int streamLength = (int)context.ContentLength;

  19:             byte[] fileData = new byte[streamLength + 1];

  20:             fileStream.Read(fileData, 0, streamLength);

  21:             using (Stream file = File.OpenWrite(@"G:\MTOMFile.jpg"))

  22:             {

  23:                 CopyStream(fileStream, file);

  24:             }

  25:             fileStream.Close();

  26:             return fileData;

  27:         }

  28:  

  29:         public static void CopyStream(Stream input, Stream output)

  30:         {

  31:             byte[] buffer = new byte[8 * 1024];

  32:             int len;

  33:             while ((len = input.Read(buffer, 0, buffer.Length)) > 0)

  34:             {

  35:                 output.Write(buffer, 0, len);

  36:             }

  37:         }

  38:     }

  39:  

  40: }

4. The Web.Config file settings for this service as follows

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:   <system.serviceModel>

   4:     <protocolMapping>

   5:       <add scheme="http" binding="wsHttpBinding" />

   6:     </protocolMapping>

   7:     <bindings>

   8:       <wsHttpBinding>

   9:         <binding messageEncoding="Mtom"/>

  10:       </wsHttpBinding>

  11:     </bindings>

12: <!--For debugging purposes set

the includeExceptionDetailInFaults attribute to true-->

  13:     <behaviors>

  14:       <serviceBehaviors>

  15:         <behavior>

  16:           <serviceMetadata httpGetEnabled="True"/>

  17:           <serviceDebug includeExceptionDetailInFaults="False" />

  18:         </behavior>

  19:       </serviceBehaviors>

  20:     </behaviors>

  21:   </system.serviceModel>

  22: </configuration>

5. To Enable send and receive MTOM messages, set the messageEncoding attribute on the binding configuration.
 
6. Add the service reference to a client project as follows
 
image

Create service client object and call the uploadfile method in client project.

   1: static void Main(string[] args)

   2:        {

   3:  

   4:            byte[] imageData = ReadFile(@"C:\Data\TestFile.jpg"); 

   5:            MemoryStream stream = new MemoryStream(imageData);

6: MTOMServiceClient.ServiceClient client = new

MTOMServiceClient.ServiceClient();

   7:  

   8:            byte[] data =  client.UploadFile(stream);

   9:            Console.WriteLine(data.Length);

  10:            Console.WriteLine();

  11:            stream.Close();

  12:  

13: // Compare the wire representations of messages

with different payloads

  14:            CompareMessageSize(data.Length);

  15:            

  16:            Console.WriteLine();

  17:            Console.WriteLine("Press <ENTER> to terminate client.");

  18:            Console.ReadLine();

  19:  

  20:         

  21:        }

Above code reading a file from disk and uploading the stream to service method. We can also compare the payload size how it looks when we used the normal text encoding and MTOM encoding.

The CompareMessageSize method code look as below

   1: static void CompareMessageSize(int dataSize)

   2: {

   3:     // Create and buffer a message with a binary payload

   4:     byte[] binaryData = new byte[dataSize];

   5:Message message = Message.CreateMessage(MessageVersion.Soap12WSAddressing10,

   6:    "action", binaryData);

   7:     MessageBuffer buffer = message.CreateBufferedCopy(int.MaxValue);

   9:     // Print the size of a text encoded copy

  10:     int size = SizeOfMtomMessage(buffer.CreateMessage());

  11:     Console.WriteLine("Text encoding with a {0} byte payload: {1}", 

  12:      binaryData.Length, size);

  14:     // Print the size of an MTOM encoded copy

  15:     size = SizeOfMtomMessage(buffer.CreateMessage());

  16:     Console.WriteLine("MTOM encoding with a {0} byte payload: {1}",

  17:     binaryData.Length, size);

  19:     Console.WriteLine();

  20:     message.Close();

  21: }

SizeOfMtomMessage method code below

   1: static int SizeOfMtomMessage(Message message)

   2: {

   3:     // Create an MTOM encoder

4: MessageEncodingBindingElement element = new

MtomMessageEncodingBindingElement();

   5:     MessageEncoderFactory factory = element.CreateMessageEncoderFactory();

   6:     MessageEncoder encoder = factory.Encoder;

   7:  

   8:     // Write the message and return its length

   9:     MemoryStream stream = new MemoryStream();

  10:     encoder.WriteMessage(message, stream);

  11:     int size = (int)stream.Length;

  12:  

  13:     stream.Close();

  14:     message.Close();

  15:     return size;

  16: }

Read file method code follows

   1: static  byte[] ReadFile(string sPath)

   2:    {

   3:        //Initialize byte array with a null value initially.

   4:        byte[] data = null;//Use FileInfo object to get file size.        

   5:        FileInfo fInfo = new FileInfo(sPath);

   6:        long numBytes = fInfo.Length;//Open FileStream to read file     

   7:        //Use BinaryReader to read file stream into byte array.

   8:        FileStream fStream = new FileStream(sPath, FileMode.Open, FileAccess.Read);

9: //When you use BinaryReader, you need to supply

number of bytes to read from file.

10: //In this case we want to read entire file ,so supplying

total number of bytes.

  11:        BinaryReader br = new BinaryReader(fStream);       

  12:        data = br.ReadBytes((int)numBytes);

  13:        return data;

  14:    }

The client application config looks as below

   1: <configuration>

   2: <system.serviceModel>

   3: <bindings>

   4: <wsHttpBinding>

   5: <binding name="WSHttpBinding_IService" closeTimeout="00:010:00"

   6: openTimeout="00:010:00" receiveTimeout="00:10:00" sendTimeout="00:010:00"

   7: bypassProxyOnLocal="false" transactionFlow="false" 

   8: hostNameComparisonMode="StrongWildcard"

   9: maxBufferPoolSize="524288" maxReceivedMessageSize="65536"

  10: messageEncoding="Mtom" textEncoding="utf-8" useDefaultWebProxy="true"

  11: allowCookies="false">

  12: <readerQuotas maxDepth="32" maxStringContentLength="8192" 

  13: maxArrayLength="16384"

  14:     maxBytesPerRead="4096" maxNameTableCharCount="16384" />

  15: <reliableSession ordered="true" inactivityTimeout="00:10:00"

  16:     enabled="false" />

  17: <security mode="Message">

  18:     <transport clientCredentialType="Windows" proxyCredentialType="None"

  19:         realm="" />

  20:     <message clientCredentialType="Windows" negotiateServiceCredential="true"

  21:         algorithmSuite="Default" />

  22: </security>

  23: </binding>

  24: </wsHttpBinding>

  25: </bindings>

  26: <client>

  27: <endpoint address="http://kalyan-pc/MTOMService/MTOMService.svc"

  28: binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IService"

  29: contract="MTOMServiceClient.IService" name="WSHttpBinding_IService">

  30: <identity>

  31: <servicePrincipalName value="host/Kalyan-PC" />

  32: </identity>

  33: </endpoint>

  34: </client>

  35: </system.serviceModel>

  36: </configuration>

You only see the considerable difference when you are sending the large binary files with SOAP message using MTOM. When you send the small files using MTOM you would not see any optimization in transfer.

The point is MTOM is able to transmit the binary data as raw message with SOAP by saving the time which results the smaller messages.

Share this post :





Related Posts:

%d bloggers like this: