将大文件流式传输到 Web 服务

本文关键字:Web 服务 传输 文件 | 更新日期: 2023-09-27 18:31:00

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

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

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

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

将大文件流式传输到 Web 服务

你可以尝试一些事情,你没有提到你使用什么协议或你如何托管它,所以我假设它可能是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 的文件)。

另一种可能性是"分块",在传输之前将数据拆分为更小的片段,这可能是您所需要的。块大小(设置为 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));
    }

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

它缺乏的功能之一是支持流媒体和大文件。特别是,一条消息在发送到客户端的途中将在内存中复制多达四次。

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

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