Я хочу использовать интерфейс IRequiresRequestStream
для включения больших загрузок файлов (видеофайлов) с использованием ServiceStack (v3) и кодирования с передачей пакетов. Стандартная загрузка файла, похоже, не справляется с некоторыми из более крупных видеофайлов, которые загружаются нашими клиентами, поэтому мы хотим включить кодировку с короткими передачами для этих файлов.
Я успешно протестировал загрузку загруженного файла с кодировкой передачи, но есть ряд параметров, которые также необходимо отправить вместе с файлом.
Так как IRequiresRequestStream
обходит анализатор объектов запроса ServiceStack, любые другие параметры объекта запроса рядом с Stream
, очевидно, не заполняются. Во время работы я вижу следующие варианты:
- Параметры строки запроса, доступные через коллекцию
this.Request.QueryString
- Пользовательские параметры заголовка, доступные через коллекцию
this.Request.Headers
- Путь, доступный через
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; }
}
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();
}
Я предполагаю, что простое направление - это что-то в следующих строках, но это похоже на 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;
});
В этом сценарии я немного использовал Google для примеров RequestBinders
. Я уверен, что должны быть встроенные методы ServiceStack для разбора Path
, но я борюсь с ним. Есть ли у кого-нибудь пример, который они хотели бы поделиться?