【问题标题】:How to throw WebFaultException after StreamReader.ReadToEnd() in C# WCF REST POST?如何在 C# WCF REST POST 中的 StreamReader.ReadToEnd() 之后抛出 WebFaultException?
【发布时间】:2013-11-14 19:22:59
【问题描述】:

我有一个 WCF REST 项目,它以 WebFaultExceptions 形式返回 http 状态代码。这对于 GET 调用非常有效,但我在为 POST 调用返回 WebFaultException 时遇到问题。请求正文中的数据使用内容类型为“application/x-www-form-urlencoded;charset=utf-8”。我认为问题在于,当上下文切换出 using 子句以引发 WebFaultException 时,底层请求流已关闭。

如果我在“使用”子句之前抛出 WebFaultException,则会按预期返回异常。如果我从“using”子句中抛出 WebFaultException,则异常不会返回给客户端。

有人对如何在使用流读取器读取请求正文时成功抛出 WebFaultException 有任何建议吗?

这是我的服务器端代码的缩写版本。请注意,此示例的 httpstatuscodes 对于我的实际实现并不现实。

[WebInvoke(Method = "POST"
, UriTemplate = "urls/{id}"
, BodyStyle = WebMessageBodyStyle.WrappedRequest
)]
public string PostItem(string id, object streamdata)
{

    int _id = 0;
    if (int.TryParse(companyIdSr2, out _id))
    {
        using (System.IO.StreamReader reader = new System.IO.StreamReader(streamdata))
        {
            string body = reader.ReadToEnd();

            if(string.IsNullOrEmpty(body))
            {
                // this exception doesn't make it back to the client's request object
                ThrowError(HttpStatusCode.BadRequest, "empty body");
            }   
        }
    }
    else
    {
        // this exception is successfully returned to the client's request object
        ThrowError(HttpStatusCode.BadRequest, "invalid id");        
    }    
}

private static void ThrowError(HttpStatusCode status, string message)
{
    request_error error = new request_error
    {
        request_url = WebOperationContext.Current.IncomingRequest.UriTemplateMatch.RequestUri.OriginalString,
        error_status_code = status.ToString(),
        error_message = message,
    };

    throw new WebFaultException<request_error>(error, status);
}

public class request_error
{
    [XmlElement("request_url")]
    public string request_url { get; set; }
    [XmlElement("error_status_code")]
    public string error_status_code { get; set; }
    [XmlElement("error_message")]
    public string error_message { get; set; }
}

我已经看到了这个问题 - Wrong WebFaultException when using a Stream and closing the stream - 虽然它在一定程度上解决了这个问题,但没有回答的是不处置或关闭流是否合理。

非常感谢,

特里

【问题讨论】:

    标签: c# wcf rest post stream


    【解决方案1】:

    您链接到的question 现在已收到解决您问题的已接受答案。

    你说:

    虽然它在一定程度上解决了这个问题,但没有回答的是不处置或关闭流是否合理。

    对此,答案是:

    但最好不要在未处理的情况下离开 StreamReader,因为它无法清理任何非托管资源。

    为了支持这一点,我们在另一个 StackOverflow 线程上提供了以下答案,该线程认为为什么调用 Dispose() 很重要:https://stackoverflow.com/a/2548694/700926

    为了解决您在问题中提出的最初问题(WebFaultExceptions 不会发送回客户端),我最终按照this answer 中的建议进行操作 - 将System.IO.StreamReader 子类化并覆盖Close 所以它告诉StreamReader 只释放非托管资源而不关闭流。

    我的 WcfFriendlyStreamReader 看起来像这样:

    public class WcfFriendlyStreamReader : StreamReader
    {
        public WcfFriendlyStreamReader(Stream s) : base(s) { }
    
        public override void Close()
        {
            base.Dispose(false);
        }
    }
    

    MSDN documentation 可以看出,调用Dispose(false) 只会释放非托管资源。正如反编译器所揭示的那样,这也会导致Stream 保持打开状态,这似乎起到了作用:

    protected override void Dispose(bool disposing)
    {
      try
      {
        if (this.LeaveOpen || !disposing || this.stream == null)
          return;
        this.stream.Close();
      }
      finally
      {
        if (!this.LeaveOpen && this.stream != null)
        {
          this.stream = (Stream) null;
          this.encoding = (Encoding) null;
          this.decoder = (Decoder) null;
          this.byteBuffer = (byte[]) null;
          this.charBuffer = (char[]) null;
          this.charPos = 0;
          this.charLen = 0;
          base.Dispose(disposing);
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-21
      • 2011-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多