2017-05-25 2 views
0

Ich glaube, ich bin in ein Kaninchenloch gefallen und vermute, dass es eine viel einfachere Lösung gibt als die, die ich versuche. Grundsätzlich möchte ich in meiner .net Core MVC App eine Streaming-Videodatei von einer externen API abrufen.Wie wird eine Antwort von einem Remote-Server in .net-Core weitergeleitet?

Also das bedeutet, für alle Anfragen an meine Aktion möchte ich eine externe API-Funktion über die Leitung aufrufen. Ich muss der Anfrage einen Header hinzufügen, aber alle anderen Header, die angefordert wurden, weiterleiten, und dann, wenn ich wieder von der API gehört habe, werde ich die Antwort in ihrer Gesamtheit an den Verbraucher weiterleiten. Es ist im Grunde wie eine Weiterleitung ohne den StatusCode und fügt der umgeleiteten Quelle eine Kopfzeile hinzu.

Die Art, wie ich es mache, ist wie folgt. In meinem Controller, nenne ich eine ForwardedResponseResult:

var client = await this.FileAssetsApiContext.GetHttpClient(); 
//Copy the Headers 
foreach (var header in Request.Headers) 
{ 
    header.Value.ToList().ForEach(p => { 
     if (client.DefaultRequestHeaders.Contains(header.Key)) 
     { 
      client.DefaultRequestHeaders.Remove(header.Key); 
      client.DefaultRequestHeaders.Add(header.Key, p); 
     } 
     else 
     { 
      client.DefaultRequestHeaders.Add(header.Key, p); 
     }}); 
    } 

    var fullPath = Url.Combine(VideosRootPath, path); 
    var response = await client.GetAsync(url); 
    return new ForwardedResponseResult(response);  

Und dann habe ich eine Weiterleitungsklasse:

public class ForwardedResponseResult : ActionResult 
{ 
    public override void ExecuteResult(ActionContext context) 
    { 
     throw new NotImplementedException(); 
    } 
    public ForwardedResponseResult(HttpResponseMessage httpResponseMessage) 
    { 
     this.HttpResponseMessage = httpResponseMessage; 
    } 

    public override async Task ExecuteResultAsync(ActionContext context) 
    { 
     var responseToCopy = this.HttpResponseMessage; 
     var responseToCopyHeaders = responseToCopy.Headers.ToArray(); 
     var responseToCopyContentHeaders = responseToCopy.Content.Headers.ToArray(); 
     var streamToCopy = await responseToCopy.Content.ReadAsStreamAsync(); 
     var responseToReturnTo = context.HttpContext.Response; 
     var streamToCopyTo = responseToReturnTo.Body; 

     var headers = responseToCopy.Headers.ToArray(); 
     var contentHeaders = responseToCopy.Content.Headers.ToArray(); 
     var headersTo = responseToReturnTo.Headers.ToArray(); 

     foreach (var header in responseToCopy.Headers) 
     { 
       header.Value.ToList().ForEach(p => responseToReturnTo.Headers.Add(header.Key, p)); 
     } 
     responseToReturnTo.StatusCode = (int) responseToCopy.StatusCode; 

     foreach (var header in responseToCopy.Content.Headers) 
     { 
      header.Value.ToList().ForEach(p => responseToReturnTo.Headers.Add(header.Key, p)); 
     } 

     //Copy to the output buffer 
     var remainingBytes = streamToCopy.Length; 

     while (remainingBytes > 0) 
     { 
      //var bufferSize = 1024; 
      var bufferSize = 8096; 
      var buffLen = remainingBytes > bufferSize ? bufferSize : remainingBytes; 
      var buffer = new byte[buffLen]; 
      streamToCopy.Read(buffer, 0, (int)buffLen); 
      streamToCopyTo.Write(buffer, 0, (int)buffLen); 
      remainingBytes -= buffLen; 
     } 
     //streamToCopy.CopyTo(streamToCopyTo); 
     //await streamToCopyTo.FlushAsync(); 

    } 
    public HttpResponseMessage HttpResponseMessage { get; } 

} 

Dies scheint massiv übertrieben, und die Leistung für Bereichsanforderungen ist schrecklich. Fehle ich etwas Offensichtliches? Gibt es eine Möglichkeit, dies einfacher zu tun?

Antwort

1

Ich möchte eine Streaming-Videodatei von einer externen API abrufen.

Im Fall von großen Downloads möchten Sie sicher sein, HttpCompletionOption.ResponseHeadersRead zu verwenden. Otherwise, the GetAsync call is actually loading the entire response content into memory (and the .Content.ReadAsStreamAsync is not actually asynchronous).

Sie können auch the existing FileStreamResult type verwenden. So etwas sollte funktionieren:

var client = await this.FileAssetsApiContext.GetHttpClient(); 
... // Copy Request.Headers to client.DefaultRequestHeaders. 

var fullPath = Url.Combine(VideosRootPath, path); 
var response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead); 
var stream = await client.Content.ReadAsStreamAsync(); 

... // Copy response.Headers/response.Content.Headers to Response.Headers 
return File(stream, "application/octet-stream"); 

Ich weiß nicht, von einer sauberen Art und Weise Request/Response-Header zu kopieren, aber es scheint wie ein guter Ort für ein paar Hilfsmethoden.

+0

Danke Stephen. Diese Änderung funktioniert viel besser. Ich bin überrascht, dass es keine direkte Methode dafür gibt, aber zumindest funktioniert es –

Verwandte Themen