Davatar
Davatar

Reputation: 156

WCF REST Service with Stream parameter throws 400 if stream is disposed

I have a WCF REST service with a very awkward behaviour. If I use ordinary parameters, such as int and I throw any kind of WebFaultException afterwards, I don't have any issues. As an example, I can throw a 403. However, if I have a Stream as parameter, I close and/or dispose the stream and throw a WebFaultException at any later point, it always throws a 400 Bad Request instead of anything else.

Here's the config:

<system.serviceModel>
<behaviors>
  <endpointBehaviors>
    <behavior name="web">
      <webHttp />
    </behavior>
  </endpointBehaviors>
  <serviceBehaviors>
    <behavior name="MyServiceBehaviour">
      <serviceMetadata httpGetEnabled="false" httpsGetEnabled="false"/>
      <serviceDebug includeExceptionDetailInFaults="false"/>
    </behavior>
  </serviceBehaviors>
</behaviors>
<services>
  <service name="MyService" behaviorConfiguration="MyServiceBehaviour">
    <endpoint binding="webHttpBinding" name="webHttpEndpoint" contract="IMyService" behaviorConfiguration="web"/>
    <endpoint address="mex" binding="mexHttpBinding" name="mexHttpEndpoint" contract="IMetadataExchange"/>
    <host>
      <baseAddresses>
        <add baseAddress="http://localhost:9009/MyService"/>
      </baseAddresses>
    </host>
  </service>
</services>

Here's the interface IMyInterface:

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    [WebInvoke(BodyStyle = WebMessageBodyStyle.Bare, Method = "POST", ResponseFormat = WebMessageFormat.Json, UriTemplate = "Token")]
    int DoSomething(Stream stream);
}

Here's MyClass:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class CallbackRequestService : ICallbackRequestService
{
    public int DoSomething(Stream stream)
    {
        StreamReader ms = new StreamReader(stream);
        string data = ms.ReadToEnd().Trim();

        // This throws correctly a 403 Forbidden
        // throw new WebFaultException<string>("Test", HttpStatusCode.Forbidden)

        ms.close();

        // This throws a 400 Bad Request instead of 403 Forbidden,
        // because the stream was closed before this
        // throw new WebFaultException<string>("Test", HttpStatusCode.Forbidden)

        // If no exception at all happens, this correctly returns 9999,
        // regardless if the stream was closed or not
        return 9999;
    }
}

I initially used a using around the stream to ensure that it will be properly closed and disposed. However, after realizing that closing and/or disposing will end up in a 400, IF I throw any kind of exception, I don't really know if I'm supposed to close the stream at all.

Does anyone understand what's wrong here?

Upvotes: 0

Views: 321

Answers (1)

user4864425
user4864425

Reputation:

The code itself is not wrong, but success depends on the source of the stream.

The stream you are trying to close is the body of the post request. For these kind of operations you may want to work with a copy of the stream:

var ms= new MemoryStream();
stream.CopyTo(ms);
memstream.Position = 0;
using (var reader = new StreamReader(ms))
{
    string data = ms.ReadToEnd().Trim();
}

The source stream itself should be left alone. In other words, you are not supposed to close the stream. The application takes care of it for you.

Upvotes: 1

Related Questions