【发布时间】:2009-11-04 20:58:25
【问题描述】:
我们正在使用 WCF 构建一个简单的 Web 服务,我们的产品使用该服务通过 WAN 链接上传大文件。它应该是一个简单的 HTTP PUT,并且在大多数情况下都可以正常工作。
这是服务合同的简化版本:
[ServiceContract, XmlSerializerFormat]
public interface IReplicationWebService
{
[OperationContract]
[WebInvoke(Method = "PUT", UriTemplate = "agents/{sourceName}/epoch/{guid}/{number}/{type}")]
ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream stream);
}
在这个合约的实现中,我们从stream 读取数据并将其写入文件。这很好用,所以我们为没有足够的磁盘空间来存储文件的情况添加了一些错误处理。大致如下:
public ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream inStream)
{
//Stuff snipped
try
{
//Read from the stream and write to the file
}
catch (IOException ioe)
{
//IOException may mean no disk space
try
{
inStream.Close();
}
// if instream caused the IOException, close may throw
catch
{
}
_logger.Debug(ioe.ToString());
throw new FaultException<IOException>(ioe, new FaultReason(ioe.Message), new FaultCode("IO"));
}
}
为了对此进行测试,我将一个 100GB 的文件发送到没有足够空间存储该文件的服务器。正如预期的那样,这会引发异常,但对inStream.Close() 的调用似乎挂起。我检查了它,实际发生的是对 Close() 的调用通过 WCF 管道,直到它到达 System.ServiceModel.Channels.DrainOnCloseStream.Close(),根据 Reflector 分配一个 Byte[] 缓冲区并继续从流中读取直到它位于EOF。
换句话说,Close 调用是在返回之前从流中读取整个 100GB 的测试数据!
现在我可能不需要在这个流上调用Close()。如果是这种情况,我想解释一下原因。但更重要的是,如果有人能向我解释为什么 Close() 会这样,为什么它不被视为错误,以及如何重新配置 WCF 以使这种情况不会发生,我将不胜感激。
【问题讨论】: