Я хочу использовать интерфейс 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; }
}
Веб-клиент:
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;
});
Я немного поискал в Google примеры RequestBinders
в этом сценарии. Я уверен, что должны быть встроенные методы ServiceStack для анализа Path
, но я борюсь с этим. У кого-нибудь есть пример, которым он хотел бы поделиться?