我对.NET,C#和WCF还是很陌生,我正在尝试创建一个服务,该服务将公开允许上传和下载大量对象(对象数组)的方法。我已经看过很多关于WCF中大文件传输的文章,但是我似乎找不到任何集中于上载和下载大量可序列化对象的内容。
我已经能够“破解” web.config文件中的允许的字节数和超时限制等,但是我想知道是否实际上有更好的方法来配置WCF
以获得更好的速度和内存使用率以进行此类传输。因为我已经根据测试结果配置了web.settings(如果超过了超时/字节限制,请使用一些疯狂的大数字来增加限制等),我怀疑我的配置是否有意义。
其次,我看到了一些实现选项,例如具有绑定TransferMode = Streaming or MTOM
,但我不知道它们是否完全适用于我的方案。有人可以指出我正确的方向吗?
抱歉,我的问题可能还不够好,但是您的想法将不胜感激。
以下是我的web.config设置:
<system.web>
<httpRuntime maxRequestLength="409600000" executionTimeout="360000"/>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="BasicHTTP" closeTimeout="00:01:00" receiveTimeout="01:00:00"
sendTimeout="01:00:00" maxBufferSize="655360000" maxReceivedMessageSize="655360000"
messageEncoding="Text" />
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="ServiceBehavior" name="WebService.WebService">
<endpoint address="" behaviorConfiguration="BasicEndPoint" binding="basicHttpBinding"
bindingConfiguration="BasicHTTP" name="BasicHTTP" contract="WebService.IWebService" />
</service>
</services>
<behaviors>
<endpointBehaviors>
<behavior name="BasicEndPoint">
<dataContractSerializer maxItemsInObjectGraph="65536000" />
</behavior>
</endpointBehaviors>
<serviceBehaviors>
<behavior name="ServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="204800000" />
</requestFiltering>
</security>
<modules runAllManagedModulesForAllRequests="true" />
</system.webServer>
最佳答案
当您确实在主机上具有流并且确实需要在客户端上接收流时,我建议仅将流模式用于诸如视频/音频流之类的任务。
对于其他任何任务,我都将使用缓冲模式,因为它确实更易于使用,并且因为许多有用的wcf功能都依赖于缓冲。使用具有启用的SOAP消息级安全性的流传输(例如),可能会消除流传输模式的速度优势(如果有的话)。
在您的情况下,我建议您执行一些解决方法。检查以下步骤:
尝试使用压缩。它可以极大地提高速度和资源使用率,但不能保证您的数据量始终相同。谁知道明年您的阵列是否会大100倍?因此,一年后您可能会回到这一点。
将返回一个巨型数组的方法替换为仅返回一个元素或一小范围的方法。然后,用一次GetItemsCountForDownload()和适当数量的GetElementAtIndex(int index)(或GetElementsRange(int startIndex,int endIndex))的调用替换一个GetAllStuff()方法调用。无论如何,在这一点上,您将不得不在消息大小(每个呼叫)和执行的呼叫数量之间找到某种平衡。
如果您的数据不能轻易地分成相等的小部分(例如,数组的第一个元素为10kb,第二个为15kb,第三个为338mb),则尝试将两种方法结合在一起:将数组序列化到磁盘,通过splittig压缩为磁盘一些可接受大小的零件,然后将它们一个接一个地转移。
尝试使算法的参数可调。将它们放在配置文件中,以便可以根据可用资源在每台部署计算机上调整拆分过程和压缩级别。
拆分数据和逐块下载块的便捷性的另一个好处是可以构建一些错误处理层。如果连接不稳定并且由于某种原因传输失败,则可以尝试仅重新下载一个chuk而不是所有数据。
有关建筑的一些技巧
找到合适的跨平台压缩算法。绝对可以找到满足您需求的产品。查看BZip2 for C# <-> Python和GZip for C# <-> Java。
尝试使您的体系结构对于其他程序员来说足够清晰。您可以为压缩数据传输和未压缩数据使用不同的方法(GetElementsRange,GetElementsRangeGZip,GetElementsRangeBZip2)。或者,您可以使用一种压缩类型为paramether(GetElementsRange(int startIndex,int endIndex,string compressionType)的方法。无论如何,其他程序员必须能够理解他正在接收的数据以及如何控制压缩模式。
您可以将数据拆分参数从配置文件移至方法定义,以便客户端可以自己定义。
您可以进一步实现两个步骤的体系结构。第一步:远程客户端定义请求参数(所有参数,包括压缩模式,拆分模式和所有其他参数)。第二步:接收数据。令牌怎么样?方法应如下所示:
string GetTokenForDataRequest(string compressionMode, int maxChunkSize); //additional parameters like dates range, account number an other are defined in this method only
int GetChunkCount(string token);
byte[] GetDataChunkAtIndex(string token, int index);
这里compressionMode可以是“ None”,“ BZip2”或“ GZip”;如果maxChunkSize为0,则禁用拆分(所有数据将在一个块中发送),否则将数据拆分为大小等于maxChunkSize的块(最后一个小于其他块)。因此,大致的情况如下:
远程客户端发送带有所需参数的数据请求。
您生成会话ID(令牌),保存该会话的参数并根据参数准备数据。 “准备数据”是指根据请求加载数据,创建临时文件夹,serializind数据,创建块文件并保留路径以供进一步使用。
客户端会收到一个令牌,该令牌用于所有其他检索数据的方法。
每次远程客户端通过您的方法请求数据块时,您将知道它在硬盘上的存储位置,剩余的块数等等,这要归功于所提供的令牌和持久的信息。
您可以轻松地一次与多个客户端同时处理数据传输会话(只需确保将数据块存储在不同的临时文件和文件夹中)
客户端可以重新下载任何块,您将不必从数据库(或数据来自何处)加载数据。
传输完成后,您可以擦除临时数据并释放一些资源。
不要将其视为唯一可能的解决方案。只是谷歌一下,你会发现自己的方式来解决您的任务!
关于c# - 从WCF上传和下载大量对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11858819/