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

时间:2012-04-11 22:43:00

标签: c# web-services stream asmx

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

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

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

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

3 个答案:

答案 0 :(得分:3)

您可以尝试一些事情,不要提及您使用的协议或托管方式,以便我认为它可能是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主体中,该主体被编码为基本64字符串。对这样的文件进行编码会使文件的大小增加多达皂体中的三分之二(即一个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));
    }

答案 1 :(得分:1)

ASMX网络服务是一种不应用于新开发的传统技术。

它缺少的功能之一是支持流媒体和大文件。特别是,在前往客户端的路上,一条消息将在内存中复制多达四次。

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

答案 2 :(得分:-1)

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