2017-06-07 31 views
15

我期待使用IRequiresRequestStream接口來啓用使用ServiceStack(v3)和分塊傳輸編碼的大文件上傳(視頻文件)。標準文件上傳似乎無法應付我們客戶上傳的一些較大的視頻文件,因此我們希望爲這些文件啓用分塊傳輸編碼。c#文件上傳的塊傳輸結合訪問ServiceStack中的路由參數

我已經成功測試了分塊傳輸編碼文件上傳,但還有一些參數也需要通過文件發送。

由於IRequiresRequestStream繞過ServiceStack請求對象解析器,請求對象旁邊的任何其他參數顯然不會填充。通過RequestBinder通過this.Request.Headers收集

  • 路徑

    1. 查詢字符串參數,通過this.Request.QueryString收集
    2. 自定義頭參數訪問,訪問,訪問??:作爲一個工作圍繞我可以看到下面的選項

    我已經設法實現選項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; } 
    } 
    

    Web客戶端:

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

    我猜簡單的方向走是大意如下的東西,但它似乎像一個kludge。

    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,但我很苦惱。有沒有人有他們想分享的例子?

  • 回答

    1

    最近我還調查了使用塊化傳輸與自定義標題。不幸的是,我發現它並不支持HttpWebRequest類,也不支持.NET框架。對我而言唯一的解決方案是通過TCP實現分塊傳輸HTTP通信。它並不像起步時那樣複雜。您只需打開TCP客戶端連接,根據需要格式化標題,按塊分割流併發送它。

    這裏是分塊傳輸協議的定義:

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