我的最终目标是允许将大型视频文件和流上传到配置为流式传输模式的WCF服务。我遇到的问题是我的WCF客户端只在将流读取到最后才向服务发出请求。
主要用例是将实时流中继到没有预定义终点的服务,因此在发送任何数据之前完全读取这些流是不切实际的。为了测试这个功能,我创建了一个“无限”流:
public class InfiniteStream : Stream
{
private Random _random;
public InfiniteStream()
{
_random = new Random(1);
}
public override int Read(byte[] buffer, int offset, int count)
{
_random.NextBytes(buffer);
Position += count;
return count;
}
// other unimportant methods
}
与我发现的示例一致,MessageContract用于接收流式上传:
[MessageContract]
public class ClipUpload : IDisposable
{
[MessageHeader(MustUnderstand = true)]
public long MediaId;
[MessageBodyMember(Order=1)]
public System.IO.Stream MediaStream;
// disposable implementaton
}
现在,据我所知,我的服务已正确配置为流式传输,并且可以在服务器端读取流而不会出现问题。感兴趣的服务器配置:
<basicHttpsBinding>
<binding name="A" transferMode="Streamed" maxReceivedMessageSize="4294967296" maxBufferSize="65536">
<security mode="TransportWithMessageCredential">
<message clientCredentialType="UserName" />
</security>
</binding>
</basicHttpsBinding>
感兴趣的客户端配置:
<basicHttpsBinding>
<binding name="A" transferMode="Streamed" maxBufferSize="65536">
<security mode="TransportWithMessageCredential" />
</binding>
</basicHttpsBinding>
服务器端操作很简单。在我的服务接口::
[OperationContract(IsOneWay=true)]
void UploadClip(ClipUpload upload);
实现:
public void UploadClip(ClipUpload upload)
{
using (var stream = new FileStream(@"C:\Temp\temp.mp4", FileMode.Create, FileAccess.Write))
{
upload.MediaStream.CopyTo(stream);
}
客户端也在使用简单的电话:
using(var stream = new InfiniteStream())
{
_service.UploadClip(1, stream);
}
同样,问题是客户端在完全读取流之前不发送任何流数据,这当然不会是InfiniteStream的情况。因此,流程永远不会到达服务器的UploadClip方法。对于非“无限”流,该过程有效,但是当客户端看似缓冲所有流内容时会有相当大的延迟。
答案 0 :(得分:0)
似乎Fiddler可能已经引入了自己的缓冲区。随着Fiddler关闭,流式传输的请求被正确地传递给WCF。
在相关的说明中,似乎在.NET 4.0及更低版本中,IIS中托管的流式WCF服务的服务器端缓冲是不可避免的。 ASP.NET层有自己的缓冲机制,在将消息传递给WCF之前等待消息完全接收。更多详情here。