rageit
rageit

Reputation: 3601

WCF Streaming issue with ASP.NET

I have a WCF service hosted in a ASP.NET application and am trying to upload a file from another client ASP.NET application using streaming mode. I keep getting following error:

The remote server returned an unexpected response: (400) Bad Request.

I have browsed the net to get help but to no avail.

Host configuration:

    <bindings>
      <basicHttpBinding>
        <binding name="FileTransferServicesBinding"
          transferMode="Streamed"
          messageEncoding="Mtom"
          sendTimeout="01:05:00"
          maxReceivedMessageSize="10067108864">
        </binding>
      </basicHttpBinding>
    </bindings>
    <services>
      <service behaviorConfiguration="FileTransferServiceBehavior" name="WebServiceHost.TransferService">
        <clear />
        <endpoint address="" binding="basicHttpBinding"
          bindingConfiguration="FileTransferServicesBinding" contract="WebServiceHost.ITransferService">
          <identity>
            <dns value="localhost"/>
            <certificateReference storeName="My" storeLocation="LocalMachine"
                x509FindType="FindBySubjectDistinguishedName" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange">
        </endpoint>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:11291/TransferService.svc" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="FileTransferServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

Contracts code:

[ServiceContract]
public interface ITransferService
{
    [OperationContract]
    RemoteFileInfo DownloadFile(DownloadRequest request);

    [OperationContract]
    void UploadFile(RemoteFileInfo request);

    [OperationContract]
    string TestMethod();
}

[MessageContract]
public class DownloadRequest
{
    [MessageBodyMember]
    public string FileName;
}

[MessageContract]
public class RemoteFileInfo : IDisposable
{
    [MessageHeader(MustUnderstand = true)]
    public string FileName;

    [MessageHeader(MustUnderstand = true)]
    public long Length;

    [MessageBodyMember(Order = 1)]
    public System.IO.Stream FileByteStream;

    public void Dispose()
    {
        if (FileByteStream != null)
        {
            FileByteStream.Close();
            FileByteStream = null;
        }
    }
}

Client configuration:

<bindings>
  <basicHttpBinding>
    <binding name="FileTransferServicesBinding" sendTimeout="01:05:00"
        maxReceivedMessageSize="10067108864" messageEncoding="Mtom"
        transferMode="Streamed" />
  </basicHttpBinding>
</bindings>
<client>
  <endpoint address="http://localhost:11291/TransferService.svc/"
      binding="basicHttpBinding" bindingConfiguration="FileTransferServicesBinding"
      contract="TransferServiceReference.ITransferService" name="FileTransferService"
      kind="">
    <identity>
      <dns value="localhost" />
      <certificateReference storeName="My" storeLocation="LocalMachine"
          x509FindType="FindBySubjectDistinguishedName" />
    </identity>
  </endpoint>
</client>
<behaviors>
  <serviceBehaviors>
    <behavior>
      <serviceMetadata httpGetEnabled="true" />
      <serviceDebug includeExceptionDetailInFaults="true" />
    </behavior>
  </serviceBehaviors>
</behaviors>

Client code:

ITransferService clientUpload = new TransferServiceClient();

string datetime = clientUpload.TestMethod();

var uploadRequestInfo = new RemoteFileInfo();

uploadRequestInfo.FileName = FileUpload1.FileName;
uploadRequestInfo.Length = FileUpload1.PostedFile.ContentLength;
uploadRequestInfo.FileByteStream = FileUpload1.PostedFile.InputStream;
clientUpload.UploadFile(uploadRequestInfo);

The call fails for both clientUpload.TestMethod() and clientUpload.UploadFile(uploadRequestInfo). With buffered mode clientUpload.TestMethod() is invoked so the issue is with the configuration in the streaming mode.

I'd be grateful to find any help on this matter. Thanks.

Upvotes: 4

Views: 6332

Answers (2)

nvtthang
nvtthang

Reputation: 604

I've got the same problems and I found this article explain to solve your error. http://www.c-sharpcorner.com/uploadfile/BruceZhang/stream-operation-in-wcf/.

Hope this help!

Upvotes: 2

VinayC
VinayC

Reputation: 49185

Issue is in your data contract - public System.IO.Stream FileByteStream;. Remove this member from data contract and use stream in your operation contract - for example:

[OperationContract(OneWay=true)]
void UploadFile(RemoteFileInfo request, System.IO.Stream fileData);

Quoted from Large Data and Streaming (MSDN):

You should not be using System.IO.Stream derived types inside of data contracts. Stream data should be communicated using the streaming model, explained in the following "Streaming Data" section.

Streaming Data section from the same link explains this in details.

Issue is in your data contract - public System.IO.Stream FileByteStream;. Remove this member from data contract and use stream in your operation contract - for example:

[OperationContract(OneWay=true)]
void UploadFile(RemoteFileInfo request, System.IO.Stream fileData);

Quoted from Large Data and Streaming (MSDN):

You should not be using System.IO.Stream derived types inside of data contracts. Stream data should be communicated using the streaming model, explained in the following "Streaming Data" section.

Streaming Data section from the same link explains this in details.

EDIT: Apologies - I have overlooked restrictions. You have two ways to solve the issue - use MessageContract or use multiple operations for a single transaction. Example of using multiple operations will be

[OperationContract]
Token UploadFile(System.IO.Stream fileData);

[OperationContract]
void ProvideFileInfo(Token token,  RemoteFileInfo request);

First upload the data to server and server will issue a token (e.g. guid), use the token to update other information.

More preferable way will be using MessageContract and which you have already trying. Few suggestions to trouble-shoot:

  1. If your hosting it in IIS, check maxRequestLength in web.config. Try uploading small files.
  2. Instead of using stream of PostedFile directly, store it to disk and use stream over it. Reasoning being http request stream may getting cleaned up while upload is in progress.
  3. Use tool such as fiddler and see message going over wire to the service, that may give a clue.

Upvotes: 2

Related Questions