使用Stream并关闭流时WebFaultException错误

时间:2012-11-29 09:26:15

标签: .net wcf rest exception exception-handling

我们有一个使用WCF构建的REST API。

我们使用WebFaultException处理所有异常后端,如下所示:

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

除了我们使用流做Post的一个场景外,这个工作正常。

一个例子:

[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语句中处理此流时,每当我们遇到异常时,我们都会继续:

来自Fiddler:

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的东西,这个acctualy工作。处理此问题的代码现在如下所示:

enter image description here

这解决了发送正确异常消息的问题,但是这会对我们的应用程序造成多大影响,而不是关闭或处理我们的StreamReader? 你还有其他解决方法吗?

1 个答案:

答案 0 :(得分:7)

这是因为StreamReader接管了流的“所有权”。换句话说,它使自己负责关闭源流。一旦您的程序调用Dispose或Close(在您的情况下保留using语句范围),它也将处理源流。在你的情况下调用sr.Dispose()。所以文件流已经过时了。

如果您不想这样,您可以创建一个继承自StreamReader并覆盖Close方法的新类;在Close方法中,调用Dispose(false),它不会关闭流。

你也可以使用Jon Skeet的MiscUtil库中的NonClosingStreamWrapper类,它正是为了这个目的。

但最好不要丢弃StreamReader,因为它无法清除任何非托管资源。