Как установить тип содержимого запроса в ASP.NET Core?

Я пытаюсь установить тип содержимого запроса multipart/form-data GET, который пропускает границу. Я пробовал этот код:

public class BoundaryMiddleware
{
    private readonly RequestDelegate _next;

    public BoundaryMiddleware(RequestDelegate next)
    {
        this._next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.Path.Value.Contains("api/webhook"))
        {  
            if (context.Request.ContentType == "multipart/form-data")
            { 
                context.Request.ContentType = $"multipart/form-data; boundary=\"{Guid.NewGuid()}\""; 
            }
        }

        await _next.Invoke(context);
    }
}

И файл запуска:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env,
        ILoggerFactory loggerFactory,
        IConfiguration configuration)
    {
        loggerFactory.AddDebug();
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            loggerFactory.AddDebug();
        }

        app.UseMiddleware<BoundaryMiddleware>();

        app.UseMvc();
    }
}

Однако этот код вызывает следующее исключение:

 System.IO.IOException: Unexpected end of Stream, the content may have already been read by another component. 
     at Microsoft.AspNetCore.WebUtilities.MultipartReaderStream.ReadAsync(Byte[] buffer, Int32 offset, Int32 count, CancellationToken cancellationToken)
     at Microsoft.AspNetCore.WebUtilities.StreamHelperExtensions.DrainAsync(Stream stream, ArrayPool`1 bytePool, Nullable`1 limit, CancellationToken cancellationToken)
     at Microsoft.AspNetCore.WebUtilities.MultipartReader.ReadNextSectionAsync(CancellationToken cancellationToken)
     at Microsoft.AspNetCore.Http.Features.FormFeature.InnerReadFormAsync(CancellationToken cancellationToken)
     at Microsoft.AspNetCore.Mvc.ModelBinding.FormValueProviderFactory.AddValueProviderAsync(ValueProviderFactoryContext context)
     at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ActionContext actionContext, IList`1 factories)
     at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ControllerContext controllerContext)
     at Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()

Есть ли способ изменить это? Спасибо

Обновлено: это запрос, переданный в веб-приложение:

GET /api/webhook HTTP/1.1
Host: localhost:5000
content-type: multipart/form-data
cache-control: no-cache

Редактировать 2: если я отправлю запрос как таковой, возникнет это исключение:

System.IO.InvalidDataException: Missing content-type boundary.
   at Microsoft.AspNetCore.Http.Features.FormFeature.GetBoundary(MediaTypeHeaderValue contentType, Int32 lengthLimit)
   at Microsoft.AspNetCore.Http.Features.FormFeature.InnerReadFormAsync(CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Mvc.ModelBinding.FormValueProviderFactory.AddValueProviderAsync(ValueProviderFactoryContext context)
   at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ActionContext actionContext, IList`1 factories)
   at Microsoft.AspNetCore.Mvc.ModelBinding.CompositeValueProvider.CreateAsync(ControllerContext controllerContext)
   at Microsoft.AspNetCore.Mvc.Internal.ControllerBinderDelegateProvider.<>c__DisplayClass0_0.<<CreateBinderDelegate>g__Bind|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
   at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)

На ваш вопрос сложно ответить без звонка в сервис, по ошибке похоже, что поток уже прочитан, нужно установить поток в начало перед попыткой его прочитать.

Rav 12.06.2019 11:27

зачем вам вводить этот идентификатор? Я имею в виду, что вы можете сделать это в своем действии контроллера, пусть маршрутизация сделает свое дело.

SilentTremor 12.06.2019 11:39

Вы не можете просто добавить случайный идентификатор границы. Этот идентификатор должен использоваться во всем теле запроса, чтобы это работало. – Почему бы вам вместо этого не попытаться исправить ваш клиент, если он выдает неверный запрос?

poke 12.06.2019 11:39

Я не являюсь владельцем кода, который вызывает мой API, и запрос является запросом на получение, поэтому тело ничего не содержит.

frank_lbt 12.06.2019 11:40

содержимое multipart/form-data как получить? Я что-то пропустил?

SilentTremor 12.06.2019 11:43

Я знаю, что это странно, но звонящий реализовал свой API таким образом.

frank_lbt 12.06.2019 11:44

Но вопрос в том, почему вы даже пытаетесь добавить составную границу в заголовок вашего типа контента, они не отправляют вам что-то, верно?

SilentTremor 12.06.2019 12:03

Да, но без границы генерируется другое исключение: System.IO.InvalidDataException: Missing content-type boundary.

frank_lbt 12.06.2019 12:12

Вместо этого вы можете попробовать удалить заголовок. Почти уверен, что это бессмысленно для запроса GET

ste-fu 12.06.2019 12:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
9
10 135
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Для HTTP GET HTTP-заголовок Content-Type не должен иметь никакого значения, HTTP-заголовок Content-Type имеет значение требуется для установки в запросах с телом (обычно PUT и POST).

На самом деле получить можно с телом, смотрите здесь, если ваш API должен поддерживать это, удачи, но это не невозможно!

В противном случае, если ваши потребители API не отправляют тело, просто сделайте следующее:

[AllowAnonymous]
[HttpGet]
[Route("api/webhook")]
public IActionResult GetWebhook()
{
     // rock and roll 
     return Ok();
}

С тестом CURL (используйте местный)

curl -X GET "https://localhost:44395/api/webhook" -H "content-type: multipart/form-data" --verbose

Нет необходимости в этом перехватчике запросов.

Ответ принят как подходящий

Заголовки .Net HTTP, как правило, немного забавны, и фреймворк будет делать различные предположения при попытке преобразовать необработанный http-запрос в HttpRequest, а затем происходит дальнейшая обработка при вызове действия на контроллере.

Учитывая, что тела нет, нет смысла иметь заголовок Content-Type или граничное значение. Возможно, вам будет эффективнее вообще удалить заголовок.

public async Task Invoke(HttpContext context)
{
    if (context.Request.Path.Value.Contains("api/webhook"))
    {  
        if (context.Request.ContentType == "multipart/form-data")
            context.Request.Headers.Remove("Content-Type");            
    }

    await _next.Invoke(context);
}

Другие вопросы по теме