Dawid O
Dawid O

Reputation: 6341

Why does HttpClient.PostAsync appear to be sending the request as a GET rather than POST?

I've been trying to send a POST request using HttpClient without a body using the PostAsync method. However, to my utter bewildement, the request is getting sent as a GET and not a POST.

enter image description here

Naturally, the request fails with a 405 Method Not Allowed becase the server doesn't allow GET.

Code sample:

var response = await new HttpClient().PostAsync("https://api.creativecommons.engineering/v1/auth_tokens/token?client_id=adsf&client_secret=asdf&grant_type=client_credentials", null);
Console.WriteLine(response.RequestMessage);

Produces:

Method: GET, RequestUri: 'https://api.creativecommons.engineering/v1/auth_tokens/token/?client_id=adsf&client_secret=asdf&grant_type=client_credentials', Version: 1.1

Example in .NET Fiddle

I've also tried using Flurl, but lead to the same result (I am guessing it is using HttpClient under the hood).

Any ideas why PostAsync is sending the request as a GET rather than POST?


Update

This question got quite a bit of hate without offering an ounce of constructive criticism... Well done StackOverflow, really well done, so much for being more welcoming...

If you come across a similar issue, here are the three things to look for:

  1. HttpClient will automatically redirect if the response is 301 (Redirect). It won't return you 301 as a status code!
  2. As it does the redirect it changes the request from POST to GET. This is technically correct, because in order to preserve the method when redirecting the server needs to return 307 and not 301.
  3. Check the address in the code against the one in the RequestMessage. This may be obvious in some cases, but in my case, the redirect involved adding a single / not something easily visible in the debugger window!
https://api.creativecommons.engineering/v1/auth_tokens/token?client_id=adsf&client_secret=asdf&grant_type=client_credentials
https://api.creativecommons.engineering/v1/auth_tokens/token/?client_id=adsf&client_secret=asdf&grant_type=client_credentials
                                                            ^    

Upvotes: 3

Views: 2002

Answers (2)

jens
jens

Reputation: 534

When utilizing integration testing you will run into this issue due to https redirect when the default startup contains this

var opt = new RewriteOptions().AddRedirectToHttps();
app.UseRewriter(opt);
app.UseHttpsRedirection();

It's not enough to use the CustomWebApplicationFactory suggestion from Microsoft. You'll have to configure your own TestServer in your *Fixture, example below

            const string baseUrl = "https://localhost:5001";
            const string environmentName = "Test";
            var contentRoot = Environment.CurrentDirectory;

            Configuration = new ConfigurationBuilder()
                .SetBasePath(contentRoot)
                .AddJsonFile("appsettings.json")
                .AddJsonFile($"appsettings.{environmentName}.json", true)
                .AddEnvironmentVariables()
                .Build();
            
            var builder = new WebHostBuilder()
                .UseUrls(baseUrl)
                .UseContentRoot(contentRoot)
                .UseEnvironment(environmentName)
                .UseConfiguration(Configuration)
                .UseStartup<TestStartup>();

            Server = new TestServer(builder) {BaseAddress = new Uri(baseUrl)};

Additionally if you follow DDD and have your Controllers in a different project, make sure your API project contains Assembly reference

services.AddControllers(options =>
                    options.Filters.Add(new HttpResponseExceptionFilter()))
                .AddApplicationPart(typeof(Startup).Assembly)
                .AddApplicationPart(typeof(MyController).Assembly);

Upvotes: 0

Timothy Stepanski
Timothy Stepanski

Reputation: 1196

I posted null to that body, looks like it is throwing a 405 and returning some information to look into. I believe the display of "GET" is deceiving.

EDIT: Ok, so to revise:

First the post executes and receives a 301 from the server.

Fiddler showing a POST with a 301 response

Followed by a redirect to another endpoint (as a GET) with the result of 405. Thus, the net result of your request manifested as a GET with a 405. My mistake.

enter image description here

Upvotes: 1

Related Questions