Using MTOM with WCF

Suppose you want to transmit large binary contents (a file, for example) through WCF. In the usual way, you would use a classe decorated with a [DataContract] attribute, and you would have inside of it a property of type Byte[], marked with a [DataMember], where the actual contents would be placed. There is a problem with this solution, however: being SOAP based exclusively in text (it is just XML), if you want to send special characters inside of it, you must convert them into text, using common encoding techniques such as Basw 64. Now, WCF does this for you, you just have to supply the byte array, and it does all the work, the problem is that Base 64 typically increases the total size by 33%.

The good news is that the good guys at W3C have developed a standard, named MTOM - Message Transmission Optimization Mechanism - that allows you to send binary content over the wire as is, that is, without translation to text. You can read about it here. I will not go into details, in order to use MTOM, you must do the folowing:

  1. The method that is sending MTOM content can only receive or return classes that have the [MessageContract] attribute, not [DataContract], or "primitive" types;
  2. All the byte array properties must have a [MessageBodyMember] attribute, not [DataMember] nor [MessageHeader], and all the other properties must have a [MessageHeader] attribute;
  3. Instead of Byte[] you can also pass a Stream object, the results are the same;
  4. All eventual classes that the parameter or return classes derive from must also have the [MessageContract] attribute;
  5. In the <binding> elements for you service (both client and server), you must set the messageEncoding attribute to Mtom.

And that's it! You will notice a significant throughput increase, specially for large contents.

See this example:

[MessageContract]

public class FileResponse

{

    [
MessageHeader]

    public String Filename { get; set; }

    [MessageBodyMember]    public Byte[] Contents { get; set; }

}

[ServiceContract]

public interface IFileService

{

    [
OperationContract]    FileResponse GetFile(String filename);

}

/* client and server */

<
bindings>

    <wsHttpBinding>

        <
binding name="WsHttpMtomBinding" messageEncoding="Mtom" />

    </wsHttpBinding>

 </bindings>

/* server only */ 

<services> 

    <
service behaviorConfiguration="Behavior" name="FileService">

        <endpoint binding="wsHttpBinding" bindingConfiguration="WsHttpMtomBinding" contract="IFileService">

     </service>

</services>

/* client only */ 

<client>

    <endpoint address="http://localhost:8001/FileService.svc" binding="wsHttpBinding" bindingConfiguration="WsHttpMtomBinding" contract="IFileService" name="IFileService"/>

</client>

                             

17 Comments

  • Thanks for the information. Straight to the point and helpful.

  • Thanks, Good post.

  • Good article. Two details, as I used this method to send larger files to the server.

    Client & Server config files, add
    maxReceivedMessageSize property:


    Since I created a web service:


  • It has been a while since you posted this but I have a question, why MessageContract and not DataContract?? What advantages do you see on MessageContract if the only field is the byte array?

    Greetings.

  • Hi, Oscar!
    It's not me, believe me... :-)
    WCF requires the usage of MessageContract for more "advanced" scenarios, such as MTOM or streaming. It basically gives you more control over the formatting of the message.

  • I have copied this same code and I cannot get it to run. WCF complains about [OperationContract] FileResponse GetFile(String filename); but works fine when I do this [OperationContract] FileResponse GetFile();

    I am not sure why it has a problem with the parameter String.

    HELP!!!

  • Chris:
    Do you have a line like this at the top of your file:

    using System;

    ?

  • Superbly explained, great work!!!

  • hello,
    i want to implement your code with multipart attachment to look like this in the soap message can i

    --MIME_boundary
    Content-Type: image/tiff
    Content-Transfer-Encoding: binary
    Content-ID: 123456

    d3d3Lm1hcmNoYWwuY29taesgfSEVFES45345sdvgfszd==

  • Excellent post.. to the point !!! thanks u

  • Hi,
    i have a very similar file transfer WCF/MTOM service. It works great, but i have a problem consuming this with JAVA. Which framework could do the job? Are there any pitfalls?
    Best regards,
    Thorsten

  • Hello, Thorsten!
    I really have no idea, since I have no knowledge of Java... did you try automatically generating a Java proxy for the .NET service?
    Good luck!
    RP

  • Excellent! Its really good!!

  • What about sending multiple files at once? Can you attach more than one file to the message?

  • @hope:
    Have you tried creating a class with as many Byte[] properties as you like and having a property of that type marked as [MessageBodyMember]?

  • Hi, i have one problem, i have a webservice in cgi that has a WSDL, i take this wsdl in my project, but when i consume the webservice i receive a message that the return is a multpart/related and expect a text/xml,.

    i try use service reference and a chane the textenconding to MTOM, but when i consume the webservice say that cant creat a reader mtom.

    how can i fix?

  • These example requires

    [MessageContract]
    public class FileRequest
    {
    [MessageHeader]
    public String Filename { get; set; }
    }

    And change IFileService with these code

    [ServiceContract]

    public interface IFileService
    {
    [OperationContract]
    FileResponse GetFile(FileRequest filename);
    }

    And remember if you want work with java too, you need change wsHttpBinding for wsBasicBinding

Comments have been disabled for this content.