2009-11-04 13 views
5

Estamos usando WCF para crear un servicio web simple que nuestro producto utiliza para cargar archivos grandes a través de un enlace WAN. Se supone que es un HTTP PUT simple, y funciona bien en su mayor parte.¿Por qué WCF lee la corriente de entrada a EOF en Close()?

Aquí es una versión simplificada del contrato de servicios:

[ServiceContract, XmlSerializerFormat] 
public interface IReplicationWebService 
{ 
    [OperationContract] 
    [WebInvoke(Method = "PUT", UriTemplate = "agents/{sourceName}/epoch/{guid}/{number}/{type}")] 
    ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream stream); 
} 

En la ejecución de este contrato, se lee los datos de stream y escribirlo en un archivo. Esto funciona muy bien, por lo que agregamos un poco de manejo de errores para los casos cuando no hay suficiente espacio en el disco para almacenar el archivo. Aquí es más o menos lo que parece:

public ReplayResult PutEpochFile(string sourceName, string guid, string number, string type, Stream inStream) 
    { 
     //Stuff snipped 
     try 
     { 
      //Read from the stream and write to the file 
     } 
     catch (IOException ioe) 
     { 
      //IOException may mean no disk space 
      try 
      { 
       inStream.Close(); 
      } 
      // if instream caused the IOException, close may throw 
      catch 
      { 
      } 
      _logger.Debug(ioe.ToString()); 
      throw new FaultException<IOException>(ioe, new FaultReason(ioe.Message), new FaultCode("IO")); 
     } 
    } 

Para probar esto, estoy enviando un archivo de 100 GB a un servidor que no tiene suficiente espacio para el archivo. Como era de esperar, arroja una excepción, pero la llamada al inStream.Close() parecía bloquearse. Lo verifiqué, y lo que está sucediendo realmente es que la llamada al Close() hizo su camino a través de la tubería WCF hasta llegar a System.ServiceModel.Channels.DrainOnCloseStream.Close(), que de acuerdo con Reflector asigna un buffer Byte[] y sigue leyendo de la transmisión hasta que está en EOF.

En otras palabras, la llamada Close está leyendo los 100 GB completos de datos de prueba de la secuencia antes de volver!

Ahora puede ser que no necesite llamar al Close() en esta secuencia. Si ese es el caso, me gustaría una explicación de por qué. Pero, lo que es más importante, agradecería que alguien pudiera explicarme por qué Close() se comporta de esta manera, por qué no se considera un error y cómo reconfigurar WCF para que eso no suceda.

Respuesta

4

.Close() es una forma "segura" y "amigable" de detener su operación, y de hecho completará las solicitudes actualmente en ejecución antes de apagarse, por diseño.

Si quiere arrojar la almádena, use .Abort() en su proxy de cliente (o host de servicio) en su lugar. Eso simplemente apaga todo sin revisar y sin ser agradable a la espera de que las operaciones se completen.

+0

Gracias por la respuesta. El problema con 'ServiceHost.Abort()' es que aborta todo el servicio, no solo la llamada particular que se está procesando. Si hubiera alguna forma de que pudiera instruir a WCF para que cerrara el socket a la fuerza en respuesta a la excepción al menos de esa manera, no tendría que esperar a que la transferencia finalizara antes de que el cliente supiera que algo andaba mal. – anelson

+0

No pude encontrar ninguna forma de informar una excepción al cliente HTTP sin esperar a que el cliente termine de enviar el archivo, por lo que tuve que aceptar una interfaz que PONE un fragmento a la vez. Esperaba evitar eso, pero no veo una forma de evitarlo dada la implementación de HTTP con la que tengo que trabajar – anelson

Cuestiones relacionadas