Мы должны отправить часть файла на основании указанного HttpRange
в запросе. В ядре .Net мы можем вернуть любой объект, который наследуется от FileResult
, и у этого класса есть свойство для указания, должна ли быть включена обработка диапазона:
/// <summary>
/// Gets or sets the value that enables range processing for the <see cref="FileResult"/>.
/// </summary>
public bool EnableRangeProcessing { get; set; }
И мы можемверните эти объекты, и фреймворк автоматически обработает запрашиваемое значение «http range». Пока все лучше. Но они сознательно решили не поддерживать несколько диапазонов байтов в одном запросе, и в этом случае весь контент файла будет отправлен в ответ. ( здесь - это ссылка на мой SO вопрос относительно этой проблемы)
И в нашем случае клиент хочет отправить несколько диапазонов байтов в одном запросе.
По этой причине,У меня есть два варианта. Либо создать новый тип результата действия, который поддерживает как один, так и несколько диапазонов. Или использовать пакет Microsoft.AspNetCore.Mvc.WebApiCompatShim
, разработанный Microsoft и обеспечивающий совместимость ASP.NET Core MVC с ASP.NET Web API 2 для упрощения миграции существующих реализаций Web API.
IУже создан какой-то пользовательский тип для поддержки нескольких диапазонов, но он должен быть реорганизован, протестирован. Вот почему я подумал, что, возможно, второй подход гораздо более актуален для этого сценария.
Итак, вот шаги. Сначала я установил этот пакет. Затем добавлен звонок на AddWebApiConventions
. Это подключит HttpResponseMessageOutputFormatter
, чтобы помочь и намекает сериализатору Json
, чтобы он правильно использовал магию сериализации.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddWebApiConventions();
}
А затем просто создал новый ApiController
, который создает ответ на основе ByteRangeStreamContent
:
public class FileController : ApiController
{
[HttpGet]
[HttpHead]
[Route("download")]
public ResponseMessageResult Download(string filePath)
{
var response = Request.CreateResponse(HttpStatusCode.PartialContent);
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
response.Content = new ByteRangeStreamContent(fileStream, Request.Headers.Range, MediaTypeNames.Application.Octet);
return ResponseMessage(response);
}
}
Эта конечная точка может выполнять как однократный, так и множественный запрос диапазона http в .Net. Но в ядре .net он снова поддерживает только один диапазон байтов.
Допустим, у меня есть файл с таким содержимым:
ABCDFGHIJKLMNOPQRSYUVWXYZ
Inв случае запроса с одним байтовым диапазоном ответ:
curl -H Range:bytes=1-5 http://localhost:55348/File/download?filePath=D:\Request.txt -i
ABCDF
Но в случае запроса с несколькими байтовыми диапазонами он странным образом возвращает полный контент для первого диапазона:
curl -H Range:bytes=1-5,6-8 http://localhost:55348/File/download?filePath=D:\Request.txt -i
--51239b4a-9749-481f-a353-6cad668fb7dc
Content-Type: application/octet-stream
Content-Range: bytes 1-5/25
ABCDFGHIJKLMNOPQRSYUVWXYZ -- As you see full content is returned instead of `ABCDF`
--51239b4a-9749-481f-a353-6cad668fb7dc
Content-Type: application/octet-stream
Content-Range: bytes 6-8/25
Не могупонять, почему он не может создать соответствующий ответ в .net Core.