2017-06-07 33 views
15

Chciałbym użyć interfejsu IRequiresRequestStream, aby umożliwić przesyłanie dużych plików (plików wideo) za pomocą ServiceStack (v3) i kodowane przesyłanie kodowania. Standardowy upload plików nie radzi sobie z niektórymi większymi plikami wideo, które przesyłają nasi klienci, dlatego staramy się włączyć kodowane kodowanie transferowe dla tych plików.C# Podzielone przesyłanie plików w połączeniu z dostępem do parametrów trasy w ServiceStack

Udało mi się przetestować przesyłanie zakodowanych plików z kodowaniem transferowym, ale istnieje szereg parametrów, które również muszą zostać przesłane z plikiem.

Od IRequiresRequestStream pomija parser obiektów żądań ServiceStack, inne parametry w obiekcie żądania obok Stream są oczywiście niewypełnione. Jako utwór wokół widzę następujące opcje:

  1. parametry string zapytanie, dostępny za pośrednictwem this.Request.QueryString kolekcji
  2. parametrów niestandardowy nagłówek, dostępny za pośrednictwem this.Request.Headers kolekcji
  3. Path, dostępny za pośrednictwem RequestBinder ??

Udało mi się już wdrożyć opcje 1 i 2, ale w jakiś sposób nie czuję się wystarczająco WYDAWCZY. Wolałbym korzystać z Path -> RequestDTO, ale mam problemy z RequestBinder.

Usługa:

public object Any(AttachmentStreamRequest request) 
{ 
    byte[] fileBytes = null; 

    using (var stream = new MemoryStream()) 
    { 
     request.RequestStream.WriteTo(stream); 
     length = stream.Length; 
     fileBytes = stream.ToArray(); 
    } 

    string filePath = @"D:\temp\test.dat"; 
    File.WriteAllBytes(filePath, fileBytes); 

    var hash = CalculateMd5(filePath); 
    var requestHash = this.Request.QueryString["Hash"]; 
    var customerId = this.Request.QueryString["CustomerId"]; 
    var fileName = this.Request.QueryString["FileName"]; 

    // nicer would be 
    // var requestHash = request.Hash; 
    // var customerId = request.CustomerId; 

    // save file.... 

    // return response 
    return requestHash == hash 
       ? new HttpResult("File Valid", HttpStatusCode.OK) 
       : new HttpResult("Invalid Hash", HttpStatusCode.NotAcceptable); 
} 

Zapytanie:

[Route("/upload/{CustomerId}/{Hash}", "POST", Summary = @"POST Upload attachments for a customer", Notes = "Upload customer attachments")] 
public class AttachmentStreamRequest : IRequiresRequestStream 
{ 
    // body 
    public Stream RequestStream { get; set; } 

    // path  
    public int CustomerId { get; set; } 

    // query 
    public string FileName { get; set; } 

    // query 
    public string Comment { get; set; } 

    // query 
    public Guid? ExternalId { get; set; } 

    // path 
    public string Hash { get; set; } 
} 

WebClient:

private static async Task<string> SendUsingWebClient(byte[] file, string hash, customerId) 
{ 
    var client = (HttpWebRequest)WebRequest.Create(string.Format("http://localhost.fiddler:58224/upload/{0}/{1}", customerId, hash)); 
    client.Method = WebRequestMethods.Http.Post; 
    client.Headers.Add("Cookie", "ss-pid=XXXXXXXXXXX; ss-id=YYYYYYYYYY"); 

    // the following 4 rows enable streaming 
    client.AllowWriteStreamBuffering = false; 
    client.SendChunked = true; 
    client.ContentType = "application/json"; 
    client.Timeout = int.MaxValue; 

    using (var fileStream = new MemoryStream(file)) 
    { 
     fileStream.Copy(client.GetRequestStream()); 
    } 

    return new StreamReader(client.GetResponse().GetResponseStream()).ReadToEnd(); 
} 

Zgaduję prosty kierunek podjąć jest coś wzdłuż następujące linie, ale wydaje się, jak kundel.

RequestBinders.Add(typeof(AttachmentStreamRequest), httpReq => { 
    var dto = new AttachmentStreamRequest(); 
    var segments = base.Request.PathInfo.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); 

    dto.CustomerId = segments[1].As<int32>(); 
    dto.Hash = segments[2].As<string>(); 

    // Stream copy to dto.RequestStream and other params etc.... 

    return dto; 
}); 

Zrobiłem trochę Googling dla przykładów RequestBinders w tym scenariuszu. Jestem pewien, że muszą być wbudowane metody ServiceStack do analizowania Path, ale ja z tym walczę. Czy ktoś ma przykład, który chcieliby udostępnić?

Odpowiedz

1

Niedawno zbadałem również zastosowanie transferu Chunked z niestandardowymi nagłówkami. Niestety, dowiedziałem się, że nie jest on obsługiwany od razu w klasie HttpWebRequest ani w ogóle w .NET Framework. Jedynym rozwiązaniem, które zadziałało, było wdrożenie komunikacji HTTP Chunked Transfer przez TCP. To nie jest tak skomplikowane, jak się wydaje na początku. Wystarczy otworzyć połączenie klienta TCP, odpowiednio sformatować nagłówki, podzielić strumień na porcje i wysłać.

Oto definicja protokołu transferu pakietowego:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding