WCF / SVC 在使用 StreamReader 时返回 HTML 错误页面而不是 JSON

Posted

技术标签:

【中文标题】WCF / SVC 在使用 StreamReader 时返回 HTML 错误页面而不是 JSON【英文标题】:WCF / SVC Returns a HTML error page instead of JSON when StreamReader used 【发布时间】:2021-11-02 10:25:53 【问题描述】:

如果有人能最终让我摆脱痛苦,那就太好了,这让我发疯了!

我目前正在编写一个简单的 WCF / SVC REST 服务,当抛出异常时,我想返回一个带有 HTTP 状态代码的有意义的 JSON。

这一切似乎都很好。

但是,当我尝试从 POST 请求中读取表单数据 (x-www-form-urlencoded) 时,响应是通用 html 页面而不是 JSON。 这只发生在我使用 StreamReader 读取流时。

Service1.svc.cs

public class Service1 : IService1

public Customer DoWork2(Stream stream)
        
            // ************************************************************
            // If this block of code is commented out, the response is JSON.
            using (var sr = new StreamReader(stream)) // <-- Using stream reader is what causes it to return HTML error page!
            
                var body = sr.ReadToEnd();
                var nvc = HttpUtility.ParseQueryString(body);
            
            // ************************************************************

            var errorData = new ErrorData("example error", "stuff");
            throw new WebFaultException<ErrorData>(errorData, HttpStatusCode.BadRequest);
        


iService.cs

[WebInvoke(Method = "POST", UriTemplate = "/DoWork2", ResponseFormat = WebMessageFormat.Json)]
        Service1.Customer DoWork2(Stream stream);

web.config

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  https://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" />
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701" />
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+" />
    </compilers>
  </system.codedom>
  <system.serviceModel>
    <services>
      <service name="RestfulServiceExample.Service1" behaviorConfiguration="ServiceBehaviour">
        <endpoint address="" contract="RestfulServiceExample.IService1" behaviorConfiguration="webHttp" binding="webHttpBinding" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehaviour">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>

        <!--<behavior>
          --><!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment --><!--
          <serviceMetadata httpGetEnabled="true"/>
          --><!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information --><!--
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>-->


      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="webHttp">
          <webHttp />
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <!--<serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      multipleSiteBindingsEnabled="true" />-->
  </system.serviceModel>
  <!--<system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>-->
</configuration>

有谁知道为什么会发生这种情况以及我该如何解决这个问题?

谢谢!

【问题讨论】:

我的猜测是 html 是 YSOD,可能有 500 错误。检查 html 并查看内容。 错误页面的标题为“请求错误”,其中包含消息服务器在处理请求时遇到错误。异常消息是“消息对象已被释放。”。 ...... 异常堆栈跟踪是:在 System.ServiceModel.OperationContext.get_IncomingMessageProperties() 在 System.ServiceModel.Dispatcher.WebErrorHandler.ProvideFault(Exception error, MessageVersion 版本,Message&故障) 经过一番挖掘,我在 *** 上找到了这篇文章;看到这里...***.com/questions/13622537/… 看起来是因为这个...“发生这种情况是因为 StreamReader 接管了流的'所有权'。换句话说,它让自己负责关闭源流。尽快当您的程序调用 Dispose 或 Close(在您的情况下保留 using 语句范围)时,它也会处理源流。在您的情况下调用 sr.Dispose()。因此文件流在之后就死了。" 【参考方案1】:

在扯掉我的头发之后,在从其他页面中得到一些提示后,我已经找到了问题的根源。

其中一个是这里的帖子...... Wrong WebFaultException when using a Stream and closing the stream

发生这种情况是因为 StreamReader 接管了 溪流。换句话说,它使自己负责关闭 源流。一旦您的程序调用 Dispose 或 Close(离开 您的情况下的 using 语句范围)然后它将处理 源流也是如此。在您的情况下调用 sr.Dispose() 。所以文件 流之后就死了。

为了解决这个问题,我添加了另一个流变量并将原始流复制到该流中。即

var isolatedStream = new MemoryStream();
stream.CopyTo(isolatedStream);

所以方法现在看起来像这样......

public Customer DoWork2(Stream stream)
        
            var isolatedStream = new MemoryStream();
            stream.CopyTo(isolatedStream);

            using (var sr = new StreamReader(isolatedStream)) // <-- Using stream reader is what causes it to return HTML error page!
            
                var body = sr.ReadToEnd();
                var nvc = HttpUtility.ParseQueryString(body);
            
            // ************************************************************

            var errorData = new ErrorData("example error", "stuff");
            throw new WebFaultException<ErrorData>(errorData, HttpStatusCode.BadRequest);
        

响应现在按最初预期返回 JSON 错误响应。

【讨论】:

以上是关于WCF / SVC 在使用 StreamReader 时返回 HTML 错误页面而不是 JSON的主要内容,如果未能解决你的问题,请参考以下文章

WCF / SVC 在使用 StreamReader 时返回 HTML 错误页面而不是 JSON

从 System32 中的文件夹加载 XML 文件以获取 wcf (.svc) c# 代码

WCF - 在 net.tcp://..../Querier.svc 上没有可以接受消息的端点侦听

同一端点(svc 文件)上的两个休息式 WCF 合同

WCF的例子

使用ssl和客户端证书的Wcf:请求svc succes wcf调用返回403.16