2017-04-12 3 views
0

Je suis confondu avec les flux, renvoie la valeur et dispose. C'est à dire. J'utilise Stream et je veux retourner le flux de la méthode. Code suivant:Éliminer et renvoyer la valeur

public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR) 
    { 
     HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK); 
     using (var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open)) 
     { 
      length = stream.Length; 
      result.Content = new StreamContent(stream); 
      result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
      result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg"); 
      result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
      result.Content.Headers.ContentLength = length; 

      return result; 
     } 
    } 

et

public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR) 
    { 
     long length = 0; 
     HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK); 
     using (var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open)) 
     { 
      length = stream.Length; 
      result.Content = new StreamContent(stream); 
     } 

     result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
     result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg"); 
     result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
     result.Content.Headers.ContentLength = length; 

     return result; 

    } 

renvoie 504 code d'état:

ReadResponse() a échoué: Le serveur n'a pas retourné une réponse complète pour cette demande. Le serveur a renvoyé 0 octet.

, comme je comprends, le flux est disposé quand on sort de la méthode

Si je n'appelle jetez pas du tout:

public async Task<HttpResponseMessage> GetOverlayAsync(string fileUrl, string language, string strOCR) 
    { 
     long length = 0; 
     HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK); 
     var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open); 
     length = stream.Length; 
     result.Content = new StreamContent(stream); 

     result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); 
     result.Content.Headers.ContentDisposition.FileName = Path.GetFileName("_forTest.jpg"); 
     result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); 
     result.Content.Headers.ContentLength = length; 

     return result; 
    } 

parfois je reçois ce fichier est bloqué par un autre processus. Comment le faire correctement?

+0

Vos exemples compilent-ils réellement? Les méthodes sont marquées comme 'async' mais il n'y a pas de' await' dans les méthodes. – Sean

+0

J'ai supprimé le code inutile avant –

+0

Essayez d'ouvrir le flux de fichier comme ceci: 'nouveau FileStream (@" D: \\ _ forTest.jpg ", FileMode.Open, FileAccess.Read, FileShare.Read);' et bien sûr ne pas Disposez-le (sera automatiquement éliminé pour vous après l'envoi au client). Quand vous faites juste 'new FileStream (..., FileMode.Open)' - c'est l'équivalent de 'nouveau FileStream (..., FileMode.Open, FileAccess.ReadWrite, FileShare.Lire) 'et cela empêchera l'ouverture ultérieure du même fichier, même à partir du même processus. – Evk

Répondre

2

Un peu d'histoire: D'une manière générale, si vous souhaitez diffuser le contenu d'un fichier, ce que vous voulez faire est lu à partir du flux de fichiers et écrire dans le flux de sortie de réponse HTTP. Exemple:

using (var source = new FileStream(...)) 
{ 
    byte[] buffer = new byte[4096]; 
    int byteCount; 
    while ((byteCount = await source.ReadAsync(buffer, 0, buffer.Length)) > 0) 
    { 
     await output.WriteAsync(buffer, 0, byteCount); 
    } 
} 

Maintenant, dans votre cas particulier, vous utilisez un cadre/modèle qui exige de vous faire passer un flux avec votre contenu, au lieu de vous permettre d'écrire à la sortie vous-même. Dans ce scénario, vous êtes obligé de transférer la responsabilité de la disposition du flux à l'invocateur de votre méthode de gestionnaire.

Spécificités: Si votre problème est le fichier verrouillé, vous pouvez autoriser partagé votre accès en lecture/écriture lorsque vous ouvrez le flux:

var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 

Cela permettra à d'autres processus de lecture et en écriture accéder au fichier pendant que vous le lisez.

EDIT: Comme l'a noté @Evk, une option plus sûre est que l'accès au partage avec les lecteurs (tentatives d'ouvrir le fichier pour l'écriture sera refusée):

var stream = new FileStream(@"D:\\_forTest.jpg", FileMode.Open, FileAccess.Read, FileShare.Read); 

Améliorations: Si votre fichier s'inscrit dans la mémoire, il serait sage de mem-cache au lieu de diffuser directement à partir du disque. Si vous avez des milliers de demandes simultanées pour récupérer ce fichier, votre disque deviendra un énorme goulot d'étranglement. Utiliser un cache avec la politique de rétention/expiration et lire et mettre en cache le fichier entier sur les échecs de cache. De cette façon, vous minimisez également la fenêtre dans laquelle vous avez ouvert la poignée de fichier (ouverture, lecture d'E/S linéaire, fermeture, très rapide).

+0

C'est vrai, mais il est préférable de spécifier 'FileShare.Read', car vous ne voulez pas vraiment que quelqu'un écrive dans le fichier pendant que vous lisez, et vous n'avez pas besoin de cela surtout dans ce scénario particulier. – Evk

+0

Bon point, mais ça dépend. Voulez-vous que vos écritures soient bloquées lors de la tentative de mise à jour du fichier? Ou est-ce OK si un utilisateur obtient une image corrompue, mais vous pouvez mettre à jour l'image sans arrêter votre serveur? –

+0

Je pense que ce n'est jamais OK si "certains utilisateurs obtiennent une image corrompue" :) – Evk