使用流模式传输大型数据
WCF 支持两种消息处理模式:
缓冲模式:WCF处理消息的默认方式,在缓冲模式下,整个消息都会保存在内存中,知道发送或者接收完成。此模式作为默认方式,在某些情况下是必需的,如可靠消息传送和数字签名,但存在的缺陷是如果消息数据过大,缓冲占用大量系统内存,同时消耗其他系统资源。
流模式:使用System.IO.Stream 来发传送消息,流模式通常在绑定或传输信道上打开,在绑定的配置上设置transferMode属性来控制流模式的粒度。
transferMode的属性值包括:Buffer、Streamed、StreamedResponse、StreamedRequest;
Demo
Contract:
[ServiceContract] public interface IFileDownload { [OperationContract] Stream GetFileStream(string fileName); }
Service:
public class FileDownloadService : IFileDownload, IDisposable { private FileStream fStream = null; public Stream GetFileStream(string fileName) { string filePath = AppDomain.CurrentDomain.BaseDirectory + fileName; if (!File.Exists(filePath)) { throw new ArgumentException(string.Format("无法找到文件名为{0}的文件", fileName)); } fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); return fStream; } public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { //被客户直接调用的,那么托管的,和非托管的资源都可以释放 if (disposing) { // 释放 托管资源 fStream.Dispose(); //垃圾回收器从Finalization队列中清除自己,从而阻止垃圾回收器调用Finalize方法. GC.SuppressFinalize(this); } } }
Config
<service name="JerryShi.EssentialWCF.FileDownloadService" behaviorConfiguration="StockServiceBehavior"> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:809/FileDownloadService"/> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" contract="JerryShi.EssentialWCF.IFileDownload" bindingConfiguration="EnableStreamingOnNetTcp" /> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> </service> </services> <bindings> <netTcpBinding> <binding name="EnableStreamingOnNetTcp" transferMode="Streamed" /> </netTcpBinding> </bindings>
说明
运行过程中出现一次异常,异常如下:
此异常由于Client端配置与Server端配置不匹配导致的
<binding name="NetTcpBinding_IFileDownload" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Streamed" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Transport"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> <message clientCredentialType="Windows" /> </security> </binding>