-->

04/08/2013

Mtom Encoding in WCF

In this post we will cover
  • What is MTOM Encoding
  • MTOM Vs Text Encoding
  • Reasons to choose MTOM
  • Demo

MTOM (Message Transmission Optimization Mechanism) – WCF supports 3 encodings (in context of WCF, encoding means converting a WCF message (serialized XML InfoSet) into bytes) – Text, MTOM & Binary. All Http Bindings (Basic, WS, Dual, etc.) support Text / MTOM encoding, Text being the default one.

Why MTOM?
Problem with Text Encoding is it uses base 64 encoding format which can inflate the message size by 30%. This can be a heavy penalty while carrying large binary attachments.
On the otherhand, MTOM avoids base 64 encoding for binary attachments keeping the overall size of message in control. Moreover, MTOM is based on open specifications & hence is largely interoperable.

Enough of theory... Let's do a demo to concretize the concept.

For this, i have created a simple WCF service. Below image will describe what we intend to do.






Contract :
namespace TestMTOM
{
    using System.Runtime.Serialization;
    using System.ServiceModel;

    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        Result GetData(string value);
    }

    [DataContract]
    public class Result
    {
        [DataMember]
        public string Message { get; set; }

        [DataMember]
        public byte[] FileContent { get; set; }
    };
}

Service Implementation:
namespace TestMTOM
{
    using System.IO;
    using System.ServiceModel.Activation;

    [AspNetCompatibilityRequirements
        (RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class Service1 : IService1
    {
        private byte[] FileToByteArray(string fileName)
        {
            byte[] buff = null;
            FileStream fs = new FileStream(fileName, 
                FileMode.Open, FileAccess.Read);
            BinaryReader br = new BinaryReader(fs);
            long numBytes = new FileInfo(fileName).Length;
            buff = br.ReadBytes((int)numBytes);
            return buff;
        }

        public Result GetData(string value)
        {
            return new Result
                {
                    Message = string.Format("Hi {0}, File Received.", value),
                    FileContent = this.FileToByteArray(@"c:\sample.pdf")
                };
        }
    }
}

Configuration:
x<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
    <bindings>
      <wsHttpBinding>
        <binding name="SecureHttpBinding"  messageEncoding="Text" closeTimeout="00:10:00" openTimeout="00:10:00" sendTimeout="00:10:00" maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647">
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647" />
          <security mode="None">
            <transport clientCredentialType="Windows" />            
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Servicebehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
          <dataContractSerializer maxItemsInObjectGraph="2147483647" />          
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="Servicebehavior" name="TestMTOM.Service1">
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="SecureHttpBinding" name="SecureHttp" contract="TestMTOM.IService1" />
        <endpoint address="mex" binding="mexHttpBinding" name="Mex" contract="IMetadataExchange" />
        <host>
          <timeouts closeTimeout="00:10:00" openTimeout="00:10:00" />
        </host>
      </service>
    </services>
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
        <directoryBrowse enabled="true" />
  </system.webServer>  
</configuration>

Client Code:
I have created a simple Windows Forms application shown below.

Code:
namespace MTOMClient
{
    using MTOMClient.MTOMSvc;

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            LblMessage.Text = string.Empty;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MTOMSvc.Service1Client client = new Service1Client();
            string name = tbName.Text;
            var result = client.GetData(name);
            LblMessage.Text = result.Message;
        }
    }
}

I executed client code and got the result, i tracked this call on fiddler. Observe the Highlighted parts of the response.


You can see that the binary content of the file is part of SOAP envolope. Now imagine a scenario where you need to log every call to your WCF service. Server will run into out of memory exception with in no time.

To sepearte the huge byte array of file content from the SOAP envolope, Mtom encoding has to be used. For this just change the below atttribute value in <Binding> tag.
                           messageEncoding="Mtom"
Once the message encoding changed to Mtom, i executed the client and tracked the call on fiddler. Now look at the response.

Now, i will explain each part:
Content Type: multipart / related
This says that the response is divided into multiple parts and the huge array of bytes were seperated from SOAP envolope and reffered with blue color part highlited in above screen shot.

<s:Envolope>
You can see that the SOAP envolope got closed in the same screenshot and the content is reffered seperately. Compare it with the earlier screen shote with "Text" message encryption, the <s:Envolope> tag has huge content inside , thus making it tough for logging.

<GetDataResult>
Represents the actual result in SOAP body.

<b:FileContent>
Represents the byte array of a huge pdf file. Thanks to Mtom encryption, now the content is seperated, so that you can log the whole SOAP message thus making it easy for logging, and every aspect of the call can be tracked in this case.

Content-ID: <http://tempuri.org/1/635113188588698327>
Represents the Mtom encoded byte array generated from huge pdf file.

Now lets talk about size of the received message, which is a crucial aspect in performance and network perspective.
The below image will speak for itself.
Thus we demonstrated the significant outcome of using Mtom encryption while using WCF services.

Code Sample :
Search for Mtom.zip in here.

1 comment:

  1. Hi, nice description about Mtom Encoding in WCF .Thanks for your help..

    -Aparna
    Theosoft

    ReplyDelete