none
MTOM Example in WCF Samples

    Question

  •  

    I've seen quite a few posts on large file/upload/attachment issues but none appear to have addressed the single parameter/single contract issue with clear best practice advice and sample code.

     

    It seems like a pretty common scenario that you would want at least one piece of metadata associated  with the upload and sticking that at the front of the data isn't really a good option so message header parameters seems to be the best route.

     

    The MTOM sample (WCF Samples) appears to be the closest sample so I am using that as an example in this case.  It does not currently have any metadata associated with the Stream and my goal is to send a simple int ID along with the message.

     

     I have tried to decorate the MTOM OperationContract with [MessageHeader] but the compiler complains "Attribute 'MessageHeader' is not valid on this declaration type..."

     

    [OperationContract]

    int Upload([MessageHeader] int id, Stream data);

     

    I'm trying to drive adoption of this stuff and I love the powerful model so I'm really hoping that I don't have to get the message recipient to drop down to a lower message level to start adding/retrieving raw text headers from the message just to grab a parameter. 

     

    Anyone shed some light on this scenario and maybe give a working example using the MTOM sample?

     

    Many Thanks,

     

    Brian

     

    Wednesday, March 28, 2007 5:55 AM

Answers

All replies

  • You want to use a MessageContract.  See http://msdn2.microsoft.com/en-us/library/ms730255.aspx

    You'll have e.g. a MessageContract class with a [MessageHeader] int field and a [MessageBodyMember] Stream field, and make that type be the parameter type of the method, for example.

    Wednesday, March 28, 2007 6:10 AM
  •  

    OK so the Service Contract for the MTOM sample would now look like this:

     

    [ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]

    public interface IUpload

    {

             [OperationContract]

             int Upload(UploadPackage package);

    }

     

    [MessageContract]

    public class UploadPackage

    {

           [MessageHeaderpublic int id;

           [MessageBodyMemberpublic Stream data;

    }

     

     

    And the bindings (MTOM Encoding, streaming) all are unchanged.  This will still stream using MTOM encoding?

    Obviously need to regenerate proxies.

     

    Great, Thanks for the speedy reply.

     

    Brian

    Wednesday, March 28, 2007 6:56 AM
  • You'll also have to change the return type to 'UploadResult' where UploadResult is a new MessageContract class you author that just has a single int member.  (An annoying constraint of the MessageContract programming model is that if you use it on the parameters you must also use it on the result, and vice-versa.)

    Other than that, yes, I think everything will 'just work'.

    Wednesday, March 28, 2007 7:15 AM
  •  

    OK I'll give that a run and post back with any other updates

     

    Thanks again,

     

    Brian

    Wednesday, March 28, 2007 7:21 AM
  •  

    So below is the updated service code for the MTOM sample (WCFSamples\TechnologySamples\Basic\Binding\WS\MTOM) with an additional parameter Id passed in the message header.

     

    Also, interesting that when the proxy is generated for the client, the message header detail is hidden so the client call looks like this

     

    UploadClient client = new UploadClient();

    Console.WriteLine(client.Upload(7,stream));

     

     

    Thanks again Brian.

     

    Brian

     

    // Service contract for an upload service

    [ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]

    public interface IUpload

    {

       [OperationContract]

       UploadResult Upload(UploadPackage package);

    }

     

    [MessageContract]

    public class UploadPackage

    {

       [MessageHeader]

       public int id;

       [MessageBodyMember]

       public Stream data;

    }

     

    [MessageContract]

    public class UploadResult

    {

       [MessageHeader]

       public int size;

    }

     

    // An upload service which takes a Stream and an id and returns its size

    public class UploadService : IUpload

    {

       public UploadResult Upload(UploadPackage package)

       {

          UploadResult res = new UploadResult();

          int size = 0;

          int bytesRead = 0;

          byte[] buffer = new byte[1024];

          // Read all the data from the stream

          do

          {

          bytesRead = package.data.Read(buffer, 0, buffer.Length);

          size += bytesRead;

          } while (bytesRead > 0);

         package.data.Close();

         System.Diagnostics.Debug.WriteLine(String.Format("Upload for Document {0} was {1} bytes",package.id, size));

     

          res.size = size;

          return res;

       }

    }

    • Proposed as answer by SmithaR Wednesday, December 09, 2009 12:33 PM
    Thursday, March 29, 2007 3:25 AM
  • Hi,

    I have used above method for passing large files from client to server and it works great. But now I want to return list as MTOM WCF service.. Is it possible for WCF MTOM service to return the array or List....


    List<BinaryDataResponse> GetBinaryData(BinaryDataRequest dataRequest) where BinaryDataResponse and BinaryDataRequest are decorated with MessageContract Attribute.

        [MessageContract()]
        public class BinaryDataResponse : IDisposable
        {
            [MessageHeader(MustUnderstand = true)]
            public long BinaryDataCode;

            [MessageBodyMember(Order=1)]
            public byte[] BinaryData;

            //[MessageBodyMember(Order = 1)]
            //public long BinaryDataCode;

            #region IDisposable Members

            public void Dispose()
            {
            }

            #endregion
        }

        [MessageContract()]
        public class BinaryDataRequest : IDisposable
        {
            [MessageHeader(MustUnderstand = true)]
            public long DocumentCode;

            //[MessageBodyMember(Order = 1)]
            //public byte[] BinaryData;

            //[MessageBodyMember(Order = 1)]
            //public long BinaryDataCode;

            #region IDisposable Members

            public void Dispose()
            {
            }

            #endregion
        }


    Any idea ? Is there anything similar to CollectionDataContract....(MessageCollectionDataContract...:)


    Regards,
    Smitha

    Wednesday, December 09, 2009 1:02 PM