簡體   English   中英

c#文件上傳分塊傳輸結合ServiceStack中路由參數的訪問

[英]c# Chunked transfer of file upload in combination with access to route parameters in ServiceStack

我希望使用IRequiresRequestStream接口來啟用使用 ServiceStack (v3) 和分塊傳輸編碼的大文件上傳(視頻文件)。 標准文件上傳似乎無法處理我們客戶上傳的一些較大的視頻文件,因此我們希望為這些文件啟用分塊傳輸編碼。

我已經成功測試了分塊傳輸編碼文件上傳,但是還有許多參數需要與文件一起發送。

由於IRequiresRequestStream繞過了 ServiceStack 請求對象解析器,因此請求對象中與Stream一起的任何其他參數顯然不會被填充。 作為解決方法,我可以看到以下選項:

  1. 查詢字符串參數,可通過this.Request.QueryString集合訪問
  2. 自定義標頭參數,可通過this.Request.Headers集合訪問
  3. 路徑,可通過RequestBinder訪問?

我已經設法實現了選項 1 和 2,但不知何故都感覺不夠 RESTful。 我更喜歡使用Path -> RequestDTO ,但我正在努力使用RequestBinder

服務:

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);
}

請求:

[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; }
}

網絡客戶端:

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();
}

我猜想采取的簡單方向是以下幾行,但這似乎是一團糟。

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;
});

在這種情況下,我已經對RequestBinders示例進行了一些谷歌搜索。 我確信必須有內置的 ServiceStack 方法來解析Path ,但我正在努力解決它。 有沒有人想分享一個例子?

最近我還研究了使用帶有自定義標頭的分塊傳輸。 不幸的是,我發現它在 HttpWebRequest 類和 .NET Framework 中都不支持開箱即用。 唯一對我有用的解決方案是通過 TCP 實現分塊傳輸 HTTP 通信。 它並不像開始時聽起來那么復雜。 您只需要打開 TCP 客戶端連接,根據需要格式化標頭,按塊拆分流並發送。

以下是分塊傳輸協議的定義:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM