WCF: using streaming with Message Contracts

23,868

Solution 1

I finally found out what was the error: it had nothing to do with Soap versions, streams, etc... I just mispelled the name of my own service (!), using FileTransfer instead of FileTransferService.

In the end basicHttpBinding was perfectly fine, I didn't need to resort to a custom binding.

Original (bad) version:

<service 
    behaviorConfiguration="serviceBehavior"
    name="Acme.Service.FileTransfer">
    <endpoint address="" 
        name="basicHttpStream" 
        binding="basicHttpBinding"
        bindingConfiguration="httpLargeMessageStream" 
        contract="Acme.Service.IFileTransferService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

New (fixed) version:

<service 
    behaviorConfiguration="serviceBehavior"
    name="Acme.Service.FileTransferService">
    <endpoint address="" 
        name="basicHttpStream" 
        binding="basicHttpBinding"
        bindingConfiguration="httpLargeMessageStream" 
        contract="Acme.Service.IFileTransferService" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>

Still I can't say that the error message was helpful in any way to understand what was going on here....

If you are interested in the whole service, you can find more details on my blog at the following link: File Transfer with WCF

Solution 2

Do you need streaming (i.e. transfer of humonguous data amounts) both on the request and response? Or just on the response (typically: downloading a file or large data set)?

If you need only on the response, you should try to set the transfermode to "StreamedResponse":

<customBinding>
    <binding name="customHttpBindingStream">
        <textMessageEncoding messageVersion="Soap12" />
        <httpTransport transferMode="StreamedResponse" 
                       maxReceivedMessageSize="2147483647"/>
    </binding>
</customBinding>

The "Streamed" setting will stream both ways - both the request going to the server, as well as the response from the server, will be streamed. More often than not, that's not the ideal scenario.

Marc

Share:
23,868
Stefano Ricciardi
Author by

Stefano Ricciardi

www.stefanoricciardi.com/about

Updated on July 07, 2020

Comments

  • Stefano Ricciardi
    Stefano Ricciardi almost 4 years

    I am trying to use the WCF streaming with Message Contracts, because I need additional parameters beside the stream itself.

    Basically I am creating a file upload and download service, with some additional logic on top.

    Unfortunately, when I try to hit the service from the browser to check that everything is all right, I get the following error:

    Server Error in '/' Application. Operation 'UploadFile' in contract 'IFileTransferService' uses a MessageContract that has SOAP headers. SOAP headers are not supported by the None MessageVersion.

    Unfortunately googling for it did not yield any significant result that helped me. Can you guys have help me out? Here the details of the service (I have removed the download part for reason of space).

    [ServiceContract(Namespace = "http://www.acme.org/2009/04")]
    public interface IFileTransferService
    {
        [OperationContract(Action = "UploadFile")]
        void UploadFile(FileUploadMessage request);
    }
    
    [MessageContract]
    public class FileUploadMessage
    {
        [MessageHeader(MustUnderstand = true)]
        public FileMetaData Metadata { get; set; }
    
        [MessageBodyMember(Order = 1)]
        public Stream FileByteStream { get; set; }
    }
    
    [DataContract(Namespace = "http://schemas.acme.org/2009/04")]
    public class FileMetaData
    {
        [DataMember(Name="FileType", Order=0, IsRequired=true)]
        public FileTypeEnum fileType;
    
        [DataMember(Name="localFilename", Order=1, IsRequired=false)]
        public string localFileName;
    
        [DataMember(Name = "remoteFilename", Order = 2, IsRequired = false)]
        public string remoteFileName;
    }
    

    I have tried to use both basichttpbinding and a customhttp binding with not positive effect:

    <customBinding>
        <binding name="customHttpBindingStream">
            <textMessageEncoding messageVersion="Soap12" />
            <httpTransport transferMode="Streamed" maxReceivedMessageSize="2147483647"/>
        </binding>
    </customBinding>
    

    UPDATE: reading the documentation online it seems that streaming with MessageContracts should indeed be possible. Refer for example to MSDN (Large Data and Streaming):

    Programming Model for Streamed Transfers

    The programming model for streaming is straightforward. For receiving streamed data, specify an operation contract that has a single Stream typed input parameter. For returning streamed data, return a Stream reference. [...] This rule similarly applies to message contracts. As shown in the following message contract, you can have only a single body member in your message contract that is a stream. If you want to communicate additional information with the stream, this information must be a carried in message headers. The message body is exclusively reserved for the stream content.

    [MessageContract]
    public class UploadStreamMessage
    {
       [MessageHeader]
       public string appRef;
       [MessageBodyMember]
       public Stream data;
    } 
    

    I have also seen blog posts from people accomplishing services of file upload and download very similar to what I am trying to put together (for example here).

    UPDATE 2 I have tried creating a small console and self hosting the service with a basicHttpBinding and there it works like a charm. I am starting to believe that the problem might be the hosting on IIS. Any idea?

    UPDATE 3 See my own answer.

  • marc_s
    marc_s over 14 years
    Not sure - I've never seen the combination of streaming with Message contracts before..... and I've seen cases where only the download from the server was big (downloading files) and setting the TransferMode to StreamedResponse helped
  • Stefano Ricciardi
    Stefano Ricciardi over 14 years
    Yes, it works using either a Stream object or a DataContract as parameter.
  • Stefano Ricciardi
    Stefano Ricciardi over 14 years
    Marc, thank you for following up. I appreciate your effort to help me. However, it seems that streaming + MessageContracts should work. See my update on my original question.
  • marc_s
    marc_s over 14 years
    @Stefano: did any of the things Kjell-Sverre mentions in his blog post apply to you? Missing permission on the file system? HTTP maxRequestLength in web.config ??
  • Stefano Ricciardi
    Stefano Ricciardi over 14 years
    Marc, see my latest update from a few minutes ago. I have tried self hosting the service and there it works. I am now investigating which are the differences between self hosting and IIS hosting.