2012-04-11 13 views
6

Tenemos un servicio web (asmx) que toma un búfer de matriz de bytes y lo transmite a un servicio de archivos externo para su almacenamiento y archivo. Es llamado por un servicio de Windows que genera archivos bastante pequeños (3-5M), por lo que crear una matriz de bytes de ese tamaño y alimentarlo como un parámetro para la llamada al servicio web ha funcionado bien hasta ahora.Transmitir archivo grande a servicio web

Me han encomendado agregar un nuevo trabajo a la cola de archivos que generará potencialmente archivos de> 70M. Obviamente, un byte[] ese tamaño abrumará la memoria del sistema, por lo que he estado buscando soluciones. El servicio web tiene un método interno que toma un FileStream como un parámetro en lugar de un byte[], así que intenté hacer que el método FileStream salga a la superficie como un método Web. Actualicé las referencias en el servicio de Windows, pero sucede algo extraño: el parámetro FileStream tiene un especificador de espacio de nombres adjunto (algo así como CallingWindowsService.ExternalWebServiceFileManager.FileStream) y este objeto especificado no toma nombre de archivo como constructor, por lo que no puedo abrir un archivo.

Estoy totalmente en el mar en cuanto a cómo acercarme a esto. ¿Alguien más ha hecho esto? Transmite grandes cantidades de datos a un servicio web, y si es así, ¿cuál es el mejor método? Mi servicio web necesitará byte[] o FileStream.

Mirando a través de algunos de los otros mensajes, parece que MTOM (que no está familiarizado con él) podría ser una solución, pero no estoy seguro de cómo configurarlo en mis métodos web o ponerlo en funcionamiento.

Respuesta

1

ASMX los servicios web son una tecnología heredada que no debe utilizarse para nuevos desarrollos.

Una de las características que le falta es la compatibilidad con la transmisión de archivos de gran tamaño. En particular, un mensaje se duplicará en la memoria hasta cuatro veces en el camino hacia el cliente.

WCF es compatible con la transmisión de verdad.

+0

La buena noticia es que hemos decidido agregar la capacidad a un servicio WCF existente, por lo que se atiende al extremo receptor. Todavía estoy en el mar, por llamar al servicio desde mi servicio de Windows. La función que llama al servicio de transmisión de archivos toma un byte [] como parámetro, por lo que la rutina de creación de mi archivo debe devolver ese búfer. Parece que tengo que refactorizar para que el búfer se declare en la rutina de creación de archivos y esa rutina llame al servicio de forma iterativa para transmitir el archivo en fragmentos. –

+0

¿Tal vez refactorizar todo para usar Streams en lugar de matrices de bytes? MemoryStream se puede construir a partir de una matriz de bytes. –

-1

Como dijo @John Saunders, los servicios web tienen poca compatibilidad con la transmisión y el procesamiento de archivos de gran tamaño. Puede usar la compresión para transmitir el archivo a través del servicio web en lugar de enviar el archivo sin formato.

+0

-1: "servicios web" no tiene problemas para la transmisión de archivos. Solo los servicios web heredados de ASMX tienen ese problema. –

3

Puede intentar algunas cosas, no menciona qué protocolos usa o cómo lo aloja, así que supongo que podría ser IIS7 y su uso. En el archivo web.config del servicio web se puede añadir la siguiente lo que aumentará el tamaño del archivo permisible para la transferencia sin el error 404:

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

La segunda cosa que puede ser que desee hacer para web del servicio web. archivo de configuración para permitir la transferencia de archivos grandes:

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

Otra posibilidad:

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

El principal problema con el envío de byte [] 's sobre los servicios web es que g y poner en el cuerpo SOAP que se codifica como una cadena base 64. La codificación de archivos como este aumenta el tamaño del archivo hasta en dos tercios en el cuerpo del jabón (es decir, un archivo de 6 MB se convierte en un archivo de 9 MB por cable).

Otra posibilidad es dividir los datos en segmentos más pequeños antes de la transmisión, que pueden ser todo lo que necesita. El tamaño de fragmento (establecido en 500 KB) puede ser un factor clave para mejorar el rendimiento de la carga en función de factores como la velocidad de la red, los recursos del servidor, etc.

/// <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)); 
    } 
Cuestiones relacionadas