7

WCF で構築された REST API があります。

次のように、すべての例外バックエンドを WebFaultException で処理します。

throw new WebFaultException<string>(e.Message, HttpStatusCode.NotAcceptable);

これは、ストリームを使用して Post を実行する 1 つのシナリオを除いて、問題なく機能します。

この例:

[WebInvoke(Method = "POST", UriTemplate = "saveUser?sessionId={sessionId}&userId={userId}",
        RequestFormat = WebMessageFormat.Json,
        ResponseFormat = WebMessageFormat.Json,            
        BodyStyle = WebMessageBodyStyle.WrappedRequest)]
    [OperationContract]
    string SaveUser(string sessionId, int userId, Stream stream);

このストリームを using ステートメントで処理すると、例外が発生するたびに次のようになります。

フィドラーから:

HTTP/1.1 400 Bad Request 
  <p>The server encountered an error processing the request. The exception message is 'The message object has been disposed.'. See server logs for more details. The exception stack trace is: </p>
  <p>  at System.ServiceModel.Channels.ByteStreamMessage.InternalByteStreamMessage.get_Properties()
   at System.ServiceModel.OperationContext.get_IncomingMessageProperties()
   at System.ServiceModel.Dispatcher.WebErrorHandler.ProvideFault(Exception error, MessageVersion version, Message&amp; fault)</p>

ストリームと StreamReader が破棄されていることに関係があるようです。

次に、StreamReader を破棄するものをすべて削除しようとしましたが、これは実際に機能します。これを処理するコードは次のようになります。

ここに画像の説明を入力

これにより、正しい例外メッセージを送信するという問題は解決しますが、StreamReader を閉じたり破棄したりせずに、アプリケーションにどのような影響を与えるのでしょうか? これを解決する他の方法はありますか?

4

1 に答える 1

8

これは、StreamReader がストリームの「所有権」を引き継ぐために発生します。つまり、ソース ストリームを閉じる責任を自分自身に負わせます。プログラムが Dispose または Close を呼び出すとすぐに (using ステートメントのスコープはそのままにしておきます)、ソース ストリームも破棄します。あなたのケースで sr.Dispose() を呼び出します。したがって、ファイルストリームは後で死んでいます。

これが望ましくない場合は、StreamReader から継承する新しいクラスを作成し、Close メソッドをオーバーライドできます。Close メソッド内で、ストリームを閉じない Dispose(false) を呼び出します。

NonClosingStreamWrapperJon Skeet のMiscUtilライブラリのクラスを使用することもできます。これはまさにその目的を果たします。

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

于 2012-11-29T13:40:38.983 に答える