WebApiCompatShim неправильно обрабатывает ByteRangeStreamContent в ядре .net - PullRequest
1 голос
/ 06 ноября 2019

Мы должны отправить часть файла на основании указанного 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.

...