c#文件上传的分块传输与ServiceStack中对路由参数的访问相结合

问题描述 投票:15回答:1

我希望使用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; }
}

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,但我正在努力解决它。有没有人有他们想分享的例子?

c# .net servicestack chunked-encoding
1个回答
1
投票

最近我还研究了使用自定义标头的Chunked传输。不幸的是,我发现它在HttpWebRequest类和一般的.NET Framework中都不支持开箱即用。对我有用的唯一解决方案是通过TCP实现Chunked Transfer HTTP通信。它并不像在开始时听起来那么复杂。您只需打开TCP客户端连接,根据需要格式化标头,按块拆分流并发送。

以下是Chunked Transfer协议的定义:

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

© www.soinside.com 2019 - 2024. All rights reserved.