如果流被处理,带有 Stream 参数的 WCF REST 服务将抛出 400

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

我有一个行为非常尴尬的 WCF REST 服务。如果我使用普通参数,例如 int,然后我抛出任何类型的 WebFaultException,我没有任何问题。例如,我可以抛出 403。但是,如果我有一个 Stream 作为参数,我关闭 and/or 处理流并在以后的任何时候抛出 WebFaultException,它总是抛出 400 Bad Request 而不是其他任何东西.

配置如下:

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

这是接口 IMyInterface:

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

这是我的班级:

[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;
    }
}

我最初在流周围使用了 using 来确保它会被正确关闭和处置。然而,在意识到关闭 and/or 处理将以 400 结束后,如果我抛出任何类型的异常,我真的不知道我是否应该关闭流。

有人知道这里出了什么问题吗?

代码本身并没有错,但成功与否取决于流的来源。

您试图关闭的流是 post 请求的主体。对于这些类型的操作,您可能需要使用流的副本:

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

源流本身应该保持独立。换句话说,您不应该关闭流。该应用程序会为您处理。