2

我对 .NET、C# 和 WCF 很陌生,我正在尝试创建一个服务,该服务将公开方法以允许上传和下载大量对象(对象数组)。我看过很多关于 WCF 中大文件传输的帖子,但我似乎找不到任何专注于上传和下载大量可序列化对象的内容。

我已经能够“破解” web.config 文件以获取允许的字节数和超时限制等,但我想知道是否实际上有更好的方法来配置WCF更好的速度和内存使用以允许此类传输。因为我已经根据我的测试结果配置了 web.settings(如果超时/字节限制超过,用一些疯狂的大数字增加限制等)我怀疑我的配置是否有意义。

其次,我已经看到了一些实现选项,例如具有 binding 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>
4

2 回答 2

1

当您在主机上确实有流并且您确实需要在客户端上接收流时,我建议仅将流模式用于视频/音频流或类似任务。对于任何其他任务,我会使用缓冲模式,因为它真的更容易使用,而且许多有用的 wcf 功能都依赖于缓冲。使用启用了 SOAP 消息级安全性的流式传输(例如)可能会消除流式传输模式的速度优势(如果你曾经有过的话)。

在您的情况下,我建议您执行一些解决方法。检查以下步骤:

  • 尝试使用压缩。它可以大大提高速度和资源使用率,但不能保证你的数据量总是一样的。谁知道明年您的阵列是否会扩大 100 倍?所以一年后你可能会回到这一点。
  • 将返回一个巨型数组的方法替换为仅返回一个元素或其中一小部分元素的方法。然后将一个GetAllStuff()方法调用替换为一次 GetItemsCountForDownload( )调用和适当数量的GetElementAtIndex(int index)(或GetElementsRange(int startIndex,int endIndex))调用。无论如何,此时您必须在消息大小(每次调用)和执行的调用次数之间找到一些平衡点。
  • 如果您的数据不能轻易拆分成小的相等部分(例如数组的第一个元素是 10kb,第二个是 15kb,第三个是 338mb),那么尝试将这两种方法结合在一起:将您的数组序列化到磁盘,使用 splittig 将其压缩到一些尺寸可接受的零件,然后一个接一个地转移它们。
  • 尝试使算法的参数可调。将它们放在您的配置文件中,这样就可以根据可用资源在每台部署机器上调整拆分过程和压缩级别。
  • 拆分数据和逐块下载的另一个好处是易于构建一些错误处理层。如果连接不稳定并且由于某种原因传输失败,您可以尝试仅重新下载一个 chuk 而不是所有数据。

关于架构的一些技巧

  • 找到合适的跨平台压缩算法。绝对可以找到满足您需求的一款。查看C# <-> Python 的 BZip2C# <-> Java 的 GZip
  • 试着让你的架构对其他程序员来说足够清晰。您可以为压缩数据传输和未压缩数据(GetElementsRangeGetElementsRangeGZipGetElementsRangeBZip2)制定不同的方法。或者您可以使用压缩类型参数(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的块(最后一个将小于另一个)。所以大概的情况是这样的:

  1. 远程客户端发送带有所需参数的数据请求。
  2. You generate session id (a token), save parameters for this session and prepare data according to parameters. "Prepare data" means loading data according to request, creating temp folder, serializind data, creating chunk files and persisting paths for further usage.
  3. Client recieves a token, that is used for all other methods for retrieving data.
  4. Every time remote client request data chunk throu your methods you will know where it stored on hard disk, how many chunks left and so on - thanks to provided token and persisted info.
  5. You can easily handle simultaneous data transfer session with several clients at one time with no efforts (just make shure you store data chunks in different temp files and folders)
  6. Client is able to redownload any chunk and you will not have to load data from database (or wherever it comes from).
  7. When transfer is complete, you can wipe temp data and free some resources.

Do not look at this as at only possible solution. Just google around a little bit and you will find your very own way to solve your task!

于 2012-08-08T07:30:00.677 回答
0

您可以使用流式消息传输,但它有一些限制。
如果流式传输不适合您,您可以实现数据分页(或尝试现有实现,如WCF 数据服务)。

于 2012-08-08T07:20:29.500 回答