Home > Software engineering >  How do I actually use HttpMethodOverrideMiddleware to redirect a POST to a PUT?
How do I actually use HttpMethodOverrideMiddleware to redirect a POST to a PUT?

Time:02-04

I am using dotnet 6 Web API. I have a consumer that can only use POST or GET. So I need to redirect their POST request to my PUT endpoint. I am trying to implement HttpMethodOverrideMiddleware but can't get it to work.

Here is my program.cs:


namespace middlewareTesting
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            // Add services to the container.

            builder.Services.AddControllers();
            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();

            var app = builder.Build();
            app.UseForwardedHeaders(new ForwardedHeadersOptions
            {
                ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
            });

            app.UseHttpMethodOverride();

            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.UseSwagger();
                app.UseSwaggerUI();
            }

            app.UseHttpsRedirection();

            app.UseAuthorization();

            app.MapControllers();

            app.Run();
        }
    }
}

And here is my controller:

using Microsoft.AspNetCore.Mvc;

namespace middlewareTesting.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }

        [HttpGet(Name = "GetWeatherForecast")]
        public IActionResult Get()
        {
            return Ok("GET WAS HIT");
        }

        [HttpPost(Name = "PostWeatherForecast")]
        public IActionResult Post()
        {
            return Ok("POST WAS HIT");
        }

        [HttpPut(Name = "PutWeatherForecast")]
        public IActionResult Put()
        {
            return Ok("PUT WAS HIT");
        }
    }
}

When I use Postman and specify a header with a key of X-HTTP-Method-Override and a value of PUT, it doesn't hit the PUT method. It hits the Post method.

However, if I set a breakpoint and inspect the Request object it looks like it changed the method to PUT.

{Microsoft.AspNetCore.Http.DefaultHttpRequest}
    Body: {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestStream}
    BodyReader: {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestPipeReader}
    ContentLength: 147
    ContentType: "application/json"
    Cookies: {Microsoft.AspNetCore.Http.RequestCookieCollection}
    Form: '((Microsoft.AspNetCore.Http.DefaultHttpRequest)Request).Form' threw an exception of type 'System.InvalidOperationException'
    HasFormContentType: false
    Headers: {Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpRequestHeaders}
    Host: {localhost:7188}
    HttpContext: {Microsoft.AspNetCore.Http.DefaultHttpContext}
    IsHttps: true
    Method: "PUT"
    Path: {/WeatherForecast}
    PathBase: {}
    Protocol: "HTTP/1.1"
    Query: {Microsoft.AspNetCore.Http.QueryCollection}
    QueryString: {}
    RouteValues: {Microsoft.AspNetCore.Routing.RouteValueDictionary}
    Scheme: "https"

Is this behavior expected? Do I need to do anything in my POST method? Do I have to do anything else to get this to work?

CodePudding user response:

Can't explain why but adding UseRouting after the UseHttpMethodOverride made it work for me:

app.UseHttpMethodOverride();
app.UseRouting();
  • Related