[英]c# Chunked transfer of file upload in combination with access to route parameters in ServiceStack
I'm looking to use the IRequiresRequestStream
interface to enable large file uploads (video files) using ServiceStack (v3) and chunked transfer encoding.我希望使用
IRequiresRequestStream
接口来启用使用 ServiceStack (v3) 和分块传输编码的大文件上传(视频文件)。 The standard file upload can't seem to cope with some of the larger video files our customers are uploading, so we are looking to enable chunked transfer encoding for these files.标准文件上传似乎无法处理我们客户上传的一些较大的视频文件,因此我们希望为这些文件启用分块传输编码。
I have successfully tested the chunked transfer encoded file upload, but there are a number of parameters that also need to be sent across with the file.我已经成功测试了分块传输编码文件上传,但是还有许多参数需要与文件一起发送。
Since IRequiresRequestStream
bypasses the ServiceStack request object parser, any other parameters in the request object alongside the Stream
are obviously not populated.由于
IRequiresRequestStream
绕过了 ServiceStack 请求对象解析器,因此请求对象中与Stream
一起的任何其他参数显然不会被填充。 As a work around I can see the following options:作为解决方法,我可以看到以下选项:
this.Request.QueryString
collectionthis.Request.QueryString
集合访问this.Request.Headers
collectionthis.Request.Headers
集合访问RequestBinder
??RequestBinder
访问? I've already managed to implement options 1 and 2, but somehow neither feel quite RESTful enough.我已经设法实现了选项 1 和 2,但不知何故都感觉不够 RESTful。 I'd prefer to use the
Path -> RequestDTO
, but I'm struggling with the RequestBinder
.我更喜欢使用
Path -> RequestDTO
,但我正在努力使用RequestBinder
。
Service:服务:
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);
}
Request:请求:
[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();
}
I'm guessing the simple direction to take is something along the following lines, but it seems like a 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;
});
I've done a bit of Googling for examples of RequestBinders
in this scenario.在这种情况下,我已经对
RequestBinders
示例进行了一些谷歌搜索。 I'm sure there must be inbuilt ServiceStack methods for parsing the Path
, but I'm struggling with it.我确信必须有内置的 ServiceStack 方法来解析
Path
,但我正在努力解决它。 Does anyone have an example they would like to share?有没有人想分享一个例子?
Recently I also investigated using Chunked transfer with custom headers.最近我还研究了使用带有自定义标头的分块传输。 Unfortunately, I found out that it's not supported out-of-the-box in HttpWebRequest class nor in .NET Framework in general.
不幸的是,我发现它在 HttpWebRequest 类和 .NET Framework 中都不支持开箱即用。 The only solution that worked for me was to implement Chunked Transfer HTTP communication over TCP.
唯一对我有用的解决方案是通过 TCP 实现分块传输 HTTP 通信。 It's not as complex as it sounds in the begginning.
它并不像开始时听起来那么复杂。 You just need to open TCP client connection, format the headers as needed, split your stream by chunks and send it.
您只需要打开 TCP 客户端连接,根据需要格式化标头,按块拆分流并发送。
Here is the definition of Chunked Transfer protocol:以下是分块传输协议的定义:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Transfer-Encoding
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.