3

HTTP ステータス コードを WebFaultExceptions として返す WCF REST プロジェクトがあります。これは GET 呼び出しではうまく機能しますが、POST 呼び出しで WebFaultException が返されるのに問題があります。リクエスト本文のデータは、コンテンツ タイプを「application/x-www-form-urlencoded;charset=utf-8」として使用しています。問題は、コンテキストが using 句から切り替えられて WebFaultException がスローされると、基になる要求ストリームが閉じられることだと思います。

「using」句の前に 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; }
}

私はこの質問を見てきました -ストリームを使用してストリームを閉じるときの間違った WebFaultException - そして、問題にいくらか対処しますが、ストリームを破棄または閉じないことが合理的かどうかは未回答のままです。

どうもありがとう、

テリー

4

1 に答える 1

3

リンク先の質問は、あなたの質問に対応する受け入れられた回答を受け取りました。

あなたは次のように述べています:

この問題にはある程度対処していますが、ストリームを破棄したり閉じたりしないことが合理的かどうかは未回答のままです。

それに対して、答えは次のように述べています。

ただし、管理されていないリソースを消去できないため、StreamReader を破棄せずにそのままにしない方がよいでしょう。

Dispose()それを裏付けるために、呼び出しが重要である理由を主張する別の StackOverflow スレッドに関する次の回答があります: https://stackoverflow.com/a/2548694/700926

あなたの質問で尋ねた最初の問題を解決するために(WebFaultExceptions はクライアントに送り返されません)、私はこの回答System.IO.StreamReaderで提案されているようにやり遂げCloseました. .

私の WcfFriendlyStreamReader は次のようになります。

public class WcfFriendlyStreamReader : StreamReader
{
    public WcfFriendlyStreamReader(Stream s) : base(s) { }

    public override void Close()
    {
        base.Dispose(false);
    }
}

MSDN ドキュメントからわかるように、呼び出し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);
    }
  }
}
于 2013-12-15T18:35:56.350 に答える