如果流被释放,带有 Stream 参数的 WCF REST 服务会抛出 400

Posted

技术标签:

【中文标题】如果流被释放,带有 Stream 参数的 WCF REST 服务会抛出 400【英文标题】:WCF REST Service with Stream parameter throws 400 if stream is disposed 【发布时间】:2018-09-16 01:16:51 【问题描述】:

我有一个行为非常尴尬的 WCF REST 服务。如果我使用普通参数,例如 int,然后我抛出任何类型的 WebFaultException,我没有任何问题。例如,我可以抛出 403。但是,如果我有一个 Stream 作为参数,我关闭和/或处置该流并在以后的任何时候抛出一个 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 以确保正确关闭和处置它。但是,在意识到关闭和/或处置最终会以 400 结束后,如果我抛出任何类型的异常,我真的不知道我是否应该关闭流。

有人明白这里出了什么问题吗?

【问题讨论】:

【参考方案1】:

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

您尝试关闭的流是发布请求的正文。对于这些类型的操作,您可能需要使用流的副本:

var ms= new MemoryStream();
stream.CopyTo(ms);
memstream.Position = 0;
using (var reader = new StreamReader(ms))

    string data = ms.ReadToEnd().Trim();

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

【讨论】:

啊,这就解释了。我希望我是控制流的人,但处理副本解决了问题。

以上是关于如果流被释放,带有 Stream 参数的 WCF REST 服务会抛出 400的主要内容,如果未能解决你的问题,请参考以下文章

将带有额外参数的文件发送到 WCF REST 服务

在 wcf rest 服务 C# 中使用 Stream 作为输入时缺少第一个元素

WCF 调用带有接口参数的服务方法导致 SocketException

带有参数的 Wcf Restful 服务发布用户名

Restful风格wcf调用3——Stream

WCF:使用带有消息契约的流式传输