Development With A Dot

Blog on development in general, and specifically on .NET

Sponsors

News

My Friends

My Links

Permanent Posts

Portuguese Communities

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>

Comments

Sean said:

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

# May 14, 2009 1:11 PM

Vrajesh said:

Thanks, Good post.

# August 5, 2009 8:18 AM

Dan said:

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

Client & Server config files, add

maxReceivedMessageSize property:

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

Since I created a web service:

<system.web>

   <httpRuntime maxRequestLength="1048576" />

# September 24, 2009 4:35 PM

Oscar Narvaez said:

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.

# March 22, 2010 1:42 PM

Ricardo Peres said:

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.

# March 22, 2010 2:23 PM

Chris said:

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!!!

# May 17, 2010 1:54 PM

Ricardo Peres said:

Chris:

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

using System;

?

# May 17, 2010 3:24 PM

ikernels said:

Superbly explained, great work!!!

# July 15, 2010 3:17 AM

guy said:

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==

# August 6, 2010 4:11 PM

amy said:

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

# September 18, 2010 4:47 AM

Thorsten said:

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

# November 29, 2010 5:36 AM

Ricardo Peres said:

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

# November 29, 2010 5:40 AM

Mahesh said:

Excellent! Its really good!!

# February 11, 2011 8:46 AM

hope said:

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

# May 10, 2011 8:05 AM

Ricardo Peres said:

@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]?

# May 10, 2011 9:25 AM

Danilo said:

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?

# July 27, 2011 9:52 AM

Jesus Alejandro Escalera said:

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

# November 17, 2011 12:47 PM