【问题标题】:Stream Large File to Web Service将大文件流式传输到 Web 服务
【发布时间】:2012-04-11 22:43:00
【问题描述】:

我们有一个 Web 服务 (asmx),它采用字节数组缓冲区并将其流式传输到外部文件服务以进行存储和归档。它由生成相当小文件 (3-5M) 的 Windows 服务调用,因此到目前为止,创建一个该大小的字节数组并将其作为参数提供给 Web 服务调用一直运行良好。

我的任务是向文件队列中添加一个新作业,该作业可能会生成 >70M 的文件。显然byte[] 的大小会压倒系统内存,所以我一直在寻找解决方案。 Web 服务有一个内部方法,它将FileStream 作为参数而不是byte[],因此我尝试将 FileStream 方法作为 WebMethod 呈现。我已经更新了 Windows 服务中的引用,但是发生了一件奇怪的事情:FileStream 参数附加了一个命名空间说明符(类似于CallingWindowsService.ExternalWebServiceFileManager.FileStream),并且这个指定的对象没有文件名作为构造函数,所以我无法打开一个特定的文件。

我完全不知道如何处理这个问题。有没有其他人这样做过 - 将大量数据流式传输网络服务 - 如果是这样,最好的方法是什么?我的网络服务需要byte[]FileStream

查看其他一些消息,看起来 MTOM(不熟悉)可能是一个解决方案,但我不确定如何在我的 Web 方法中设置它或让它工作。

【问题讨论】:

    标签: c# web-services stream asmx


    【解决方案1】:

    你可以尝试一些事情,你没有提到你使用什么协议或你如何托管它,所以我假设它可能是 IIS7 和你使用的肥皂。在 web 服务的 web.config 文件中,您可以添加以下内容,这将增加允许传输的文件大小而不会出现 404 错误:

      <system.web>
         <httpRuntime executionTimeout="999999" maxRequestLength="2097151" />
         ...
      </system.web>
    

    您可能想要对 Web 服务的 web.config 文件执行的第二件事以允许大文件传输:

      <system.webServer>
        <security>
          <requestFiltering>
            <requestLimits maxAllowedContentLength="2000000000" />
          </requestFiltering>
        </security>
      </system.webServer>
    

    另一种可能性:

    <location path="Copy.asmx"> <!-- Name of you asmx -->
        <system.webServer>
          <security>
            <requestFiltering>
              <requestLimits maxAllowedContentLength="104857600"/> <!-- 100 megs -->
            </requestFiltering>
          </security>
        </system.webServer>
      </location>
    

    通过 Web 服务发送 byte[] 的主要问题是它们被放入 SOAP 主体中,该主体被编码为 base 64 字符串。像这样对文件进行编码会使soap主体中的文件大小增加三分之二(即,6 MB 的文件通过网络变成 9 MB 的文件)。

    另一种可能性是在传输之前将您的数据“分块”分成更小的部分,这可能就是您所需要的。根据网络速度、服务器资源等因素,chunkSize(设置为 500KB)可能是提高上传性能的关键因素。

    /// <summary>
    /// Chunk the file and upload
    /// </summary>
    /// <param name="filename"></param>
    private void UploadVideo(string filename)
    {
        #region Vars
        const int chunkSize = 512000;
        byte[] bytes = null;
        int startIndex, endIndex, length, totalChunks;           
    
        WS.UploadRequest objRequest = new WS.UploadRequest();            
        #endregion
    
        try
        {
            if (File.Exists(filename))
            {
                using (WS.UploadService objService = new WS.UploadService())
                {
                    using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
                    {
                        //// Calculate total chunks to be sent to service
                        totalChunks = (int)Math.Ceiling((double)fs.Length / chunkSize);
    
                        //// Set up Upload request object
                        objRequest.FileName = filename;
                        objRequest.FileSize = fs.Length;
    
                        for (int i = 0; i < totalChunks; i++)
                        {
                            startIndex = i * chunkSize;
                            endIndex = (int)(startIndex + chunkSize > fs.Length ? fs.Length : startIndex + chunkSize);
                            length = endIndex - startIndex;
                            bytes = new byte[length];
    
                            //// Read bytes from file, and send upload request
                            fs.Read(bytes, 0, bytes.Length);
                            objRequest.FileBytes = bytes;
                            objService.UploadVideo(objRequest);
                        }
                    }
    
                }
            }
        }
        catch (Exception ex)
        {
            MessageBox.Show(string.Format("Error- {0}", ex.Message));
        }
    

    【讨论】:

      【解决方案2】:

      ASMX Web 服务是一项遗留技术,不应用于新开发。

      它缺少的功能之一是支持流式传输和大文件。特别是,一条消息在发送到客户端的途中将在内存中最多重复四次。

      WCF 确实支持真正的流媒体。

      【讨论】:

      • 好消息是我们决定将功能添加到现有的 WCF 服务中,因此接收端得到了照顾。不过,关于从我的 Windows 服务调用该服务,我仍然在海上。调用文件传输服务的函数将 byte[] 作为参数,因此我的文件创建例程必须返回该缓冲区。听起来我需要重构,以便在文件创建例程中声明缓冲区,并且该例程迭代地调用服务以分块传输文件?
      • 也许重构一切以使用 Streams 而不是字节数组? MemoryStream 可以从字节数组构造。
      【解决方案3】:

      正如@John Saunders 所说,Web 服务对流式处理和大文件大小处理的支持很差,您可以使用压缩通过 Web 服务传输文件,而不是发送原始文件。

      【讨论】:

      • -1:“网络服务”流式传输文件没有问题。只有旧的 ASMX Web 服务有这个问题。
      猜你喜欢
      • 1970-01-01
      • 2013-01-05
      • 2018-04-02
      • 2011-05-23
      • 2017-02-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多