Как установить тип содержимого запроса в ASP.NET Core? - PullRequest
1 голос
/ 12 июня 2019

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

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)

Ответы [ 2 ]

1 голос
/ 12 июня 2019

.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);
}
0 голосов
/ 12 июня 2019

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

Действительно, get может быть с телом, см. здесь , если ваш 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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...