如何在ASP.NET Core中设置请求的内容类型?

时间:2019-06-12 09:03:23

标签: c# 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()

是否可以修改此内容?谢谢

编辑:这是传递给Web应用程序的请求:

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 个答案:

答案 0 :(得分:1)

.Net HTTP标头通常有点有趣,当尝试将原始http请求转换为HttpRequest时,框架会做出各种假设,然后在Controller上调用动作时会进行进一步处理。

鉴于没有主体,因此拥有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);
}

答案 1 :(得分:0)

对于HTTP GET,内容类型HTTP标头根本不重要,内容类型HTTP标头是required,可以在具有正文的请求上设置(通常为PUT和POST)。

实际上,get可以与主体一起使用,如果您的API需要支持这种好运,请参阅here,但这并不是不可能!

否则,如果您的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

不需要该请求拦截器。