Home > Blockchain >  HttpClient 400 bad request on PostAsync to endpoint after switching from Minimal API to MVC API
HttpClient 400 bad request on PostAsync to endpoint after switching from Minimal API to MVC API

Time:07-10

I started out with a .NET 6 minimal api which was working fine, however I needed some extra functionality, so I then decided to switch over to MVC style api. Since then, when my WPF app tries to call the endpoint using POST I get a 400 bad request. If I use swagger to make the call, it works with no problem. But using HttpClient in my WPF app gives the error. I've looked at about a dozen other questions on this error but none of the solutions seemed to fix my problem.

When I run both the API and WPF app with debugging and debug the beginning of both the UserService call to InsertUser and the API's InsertUser methods, the API's debug point never gets hit, which to me sounds like when MVC is processing the request it sees something it doesn't like and returns the 400 error, but I'm not sure why the PUT request is fine and the POST request isn't.

In my ASP.net core program.cs I added the following to enable MVC api usage

builder.Services.AddControllers();
app.MapControllers();

In my WPF app the httpClient is handled through DI and injected in my UserService class used to make the call to the endpoint.

InsertUser POST method

public async Task<bool> InsertUser(UserModel user)
{
    var result = await _httpClient.PostAsync("/api/Users",
        user.AsJsonContent());
    return result.IsSuccessStatusCode;
}

This is the UpdateUser method that uses PUT and works fine

public async Task<bool> UpdateUser(UserModel user)
{
    var result = await _httpClient.PutAsync("/api/Users", 
        user.AsJsonContent());
    return result.IsSuccessStatusCode;
}

Extension that turns the UserModel into a StringContent

public static StringContent AsJsonContent(this object obj)
{
    string json = JsonConvert.SerializeObject(obj);
    var content = new StringContent(json, Encoding.UTF8, "application/json");
    //content.Headers.Remove("Content-Type");
    //content.Headers.Add("Content-Type", "application/json");
    //content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
    return content;
}

This is a trimmed down version of my UsersController

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    [HttpPost]
    public async Task<IActionResult> InsertUser(UserModel model)
    {
        _appDbContext.Users.Add(model);
        var result = await _appDbContext.SaveChangesAsync();
        return result > 0 ? Ok() : Problem("User was not inserted");
    }

    [HttpPut]
    public async Task<IActionResult> UpdateUser(UserModel model)
    {
        if(await _appDbContext.Users.FindAsync(model.Id) is UserModel efModel)
        {
            _mapper.Map(model, efModel);
            _appDbContext.Users.Update(efModel);
            var result = await _appDbContext.SaveChangesAsync();
            return result > 0 ? Ok() : Problem("User was not updated");
        }

        return Problem("User not found.");
    }
}

This is result from PostAsync

{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
  Date: Thu, 07 Jul 2022 14:35:53 GMT
  Server: Kestrel
  Transfer-Encoding: chunked
  Content-Type: application/problem json; charset=utf-8
}}

This is my response message

{Method: POST, RequestUri: 'https://localhost:7159/api/Users', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
  Content-Type: application/json
  Content-Length: 253
}}

Edit: Adding reqested info

Here is the json responce for the bad responce

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "00-ac9fc01b742547b2525eef9de28ea6a0-d123c5b603ff637c-00",
    "errors": {
        "Token": [
            "The Token field is required."
        ]
    }
}

This was the minimal api version of InsertUser

//Registered in another class
app.MapPost("/Users", InsertUser);

public async Task<bool> InsertUser(UserModel model)
{
    await _appDbContext.Users.AddAsync(model);
    var result = await _appDbContext.SaveChangesAsync();
    return result > 0;
}

CodePudding user response:

since you are posting the data as a json content, you have to add a frombody attribute to both controller actions

   public async Task<IActionResult> UpdateUser([FromBody]UserModel model)
  • Related