WCF中作为返回值的流 - 谁负责释放它?

53

假设我有以下的WCF实现:

public Stream Download(string path)
{
    FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
    return stream;
}

谁负责处理返回值的清理?毕竟,可能会发生网络故障,因此使用者可能无法进行清理。


@Magnus,就像我上面所描述的那样,由于可能存在网络故障,消费者可能无法处理它。 - Ron Klein
5
@Magnus,猜测很好,但我想要一个确定的答案 :-) - Ron Klein
2
让消费者处理返回流对服务器端的对象引用没有影响,因为客户端获取的是对象的序列化版本,并且永远不会有对象引用到它在服务器上的位置。 - user1060500
3个回答

50

服务负责关闭流,如果不更改默认行为 (默认情况下始终使用)则会自动关闭。如果将OperationBehavior.AutoDisposeParameters设置为false,则必须为OperationContext.OperationCompleted注册处理程序,并在处理程序中按照此处所述处理流。

客户端无法关闭流,因为客户端具有不同的流 - 您未传递到流或文件处理程序的引用。内部将文件内容复制到传输并且客户端在其自己的流实例中处理它(在那里客户端有责任处置它)。


1
很好的解释,但如果您在响应消息契约中遇到未处理的流,请考虑@peter-sladek的答案,根据我的经验,我可以为此担保。 - Ferran Salguero

34

如果你在MessageContract中包装了Stream(这样你可以在标头中发送更多信息),请注意Stream不会自动释放!正如属性OperationBehavior.AutoDisposeParameters的名称所示,WCF会自动处理输入/输出参数,因此您必须在MessageContract类上实现IDisposable接口,并在那里关闭流。


1
那么你的意思是,如果我在我的响应类中有一个流属性,那么响应类需要实现IDisposable并在那里处理流的释放?换句话说,WCF将确保响应被处理,而我的责任是确保响应类代理该Dispose到流属性? - AaronLS
如果使用消息合同,是的。至少根据我在2011年的测试结果是这样的。你应该一定要进行一些测试来验证是否仍然需要。 - Peter Sladek
然后避免使用消息契约,那通常是为了进行一些细粒度的控制。大多数业务应用不需要消息契约。 - ZZZ

2
您可以像下面这样在WCF中处理返回的流。
FileStream stream=null;
OperationContext clientContext = OperationContext.Current;
clientContext.OperationCompleted += (sender, args) =>
{
    if (stream != null)
        stream.Dispose();
};

stream = new FileStream(path, FileMode.Open, FileAccess.Read);
return stream;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接