I am creating an ASP.NET Core Web API that will do CRUD for a Locations
entity. I call the API from my Blazor web assembly project, and the GET
verb I have in place works (I can list locations from my database in a .razor
component page, in a grid), but when I try to do a POST
from the same client to the same route, nothing happens. I can 'try it out' in swagger and my POST
code works (it inserts the new location), but from the web assembly client, there is no result and the new location is not inserted.
What might I be missing?
Here's my API LocationController
:
using Microsoft.AspNetCore.Mvc;
using BlazorAppDiscoveryAPI.Models;
using Microsoft.Data.SqlClient;
using Dapper;
using System.Data;
namespace BlazorAppDiscoveryAPI.Controllers
{
[ApiController]
[Route("api/Locations")]
public class LocationController : ControllerBase
{
static IConfiguration conf = (new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build());
public static string connectionString = conf["ConnectionStrings:Default"].ToString();
// This works, I can display the Locations from the db on my blazor client page.
[HttpGet(Name = "GetLocations")]
public IEnumerable<dynamic> Get()
{
string strSQL = "select * from dbo.Location";
using IDbConnection connection = new SqlConnection(connectionString);
{
return connection.Query(strSQL);
}
}
// This works in swagger, but not when called from the blazor client page. I'm not sure the client call even gets to here.
[HttpPost]
public int Add(LocationModel newLocation)
{
string strSQL = @"INSERT INTO dbo.Location(Location_NUM, Location_OWNER)
VALUES(@Location_NUM, @Location_OWNER);";
using IDbConnection connection = new SqlConnection(connectionString);
{
return connection.Execute(strSQL, newLocation);
}
}
}
}
Again, this much works in swagger for a GET
and POST
to localhost.../api/Locations/
.
From the client side: I'm calling the API from the Blazor component page:
@code {
private List<LocationModel> Locations;
private LocationModel newLocation = new LocationModel();
protected override async Task OnInitializedAsync()
{
Locations = await LocationService.GetAllLocationsAsync();
}
private async Task InsertLocation()
{
LocationModel s = new LocationModel
{
Location_NUM = newLocation.Location_NUM,
Location_OWNER = newLocation.Location_OWNER
};
await LocationService.InsertLocationAsync(s);
newLocation = new LocationModel();
}
}
Here is the LocationService.cs
, making the requests:
using BlazorAppDiscovery.Client.Models;
using System.Net.Http.Json;
using Microsoft.Extensions.Configuration;
namespace BlazorAppDiscovery.Client.Services
{
public class LocationService(HttpClient http) : ILocationService
{
public static string baseaddress = "https://localhost:7276/"; // TODO: get this from the config file.
public async Task<List<LocationModel>> GetAllLocationsAsync()
{
string requestUri = baseaddress + "api/Locations/";
return await http.GetFromJsonAsync<List<LocationModel>>(requestUri);
}
public async Task InsertLocationAsync(LocationModel newLocation)
{
string requestUri = baseaddress + "api/Locations/";
await http.PostAsJsonAsync(requestUri, newLocation);
}
}
}
What else might I have missed so that my GET
works perfectly from both the client and swagger, but the POST
only works from swagger, not the client?
I am creating an ASP.NET Core Web API that will do CRUD for a Locations
entity. I call the API from my Blazor web assembly project, and the GET
verb I have in place works (I can list locations from my database in a .razor
component page, in a grid), but when I try to do a POST
from the same client to the same route, nothing happens. I can 'try it out' in swagger and my POST
code works (it inserts the new location), but from the web assembly client, there is no result and the new location is not inserted.
What might I be missing?
Here's my API LocationController
:
using Microsoft.AspNetCore.Mvc;
using BlazorAppDiscoveryAPI.Models;
using Microsoft.Data.SqlClient;
using Dapper;
using System.Data;
namespace BlazorAppDiscoveryAPI.Controllers
{
[ApiController]
[Route("api/Locations")]
public class LocationController : ControllerBase
{
static IConfiguration conf = (new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json").Build());
public static string connectionString = conf["ConnectionStrings:Default"].ToString();
// This works, I can display the Locations from the db on my blazor client page.
[HttpGet(Name = "GetLocations")]
public IEnumerable<dynamic> Get()
{
string strSQL = "select * from dbo.Location";
using IDbConnection connection = new SqlConnection(connectionString);
{
return connection.Query(strSQL);
}
}
// This works in swagger, but not when called from the blazor client page. I'm not sure the client call even gets to here.
[HttpPost]
public int Add(LocationModel newLocation)
{
string strSQL = @"INSERT INTO dbo.Location(Location_NUM, Location_OWNER)
VALUES(@Location_NUM, @Location_OWNER);";
using IDbConnection connection = new SqlConnection(connectionString);
{
return connection.Execute(strSQL, newLocation);
}
}
}
}
Again, this much works in swagger for a GET
and POST
to localhost.../api/Locations/
.
From the client side: I'm calling the API from the Blazor component page:
@code {
private List<LocationModel> Locations;
private LocationModel newLocation = new LocationModel();
protected override async Task OnInitializedAsync()
{
Locations = await LocationService.GetAllLocationsAsync();
}
private async Task InsertLocation()
{
LocationModel s = new LocationModel
{
Location_NUM = newLocation.Location_NUM,
Location_OWNER = newLocation.Location_OWNER
};
await LocationService.InsertLocationAsync(s);
newLocation = new LocationModel();
}
}
Here is the LocationService.cs
, making the requests:
using BlazorAppDiscovery.Client.Models;
using System.Net.Http.Json;
using Microsoft.Extensions.Configuration;
namespace BlazorAppDiscovery.Client.Services
{
public class LocationService(HttpClient http) : ILocationService
{
public static string baseaddress = "https://localhost:7276/"; // TODO: get this from the config file.
public async Task<List<LocationModel>> GetAllLocationsAsync()
{
string requestUri = baseaddress + "api/Locations/";
return await http.GetFromJsonAsync<List<LocationModel>>(requestUri);
}
public async Task InsertLocationAsync(LocationModel newLocation)
{
string requestUri = baseaddress + "api/Locations/";
await http.PostAsJsonAsync(requestUri, newLocation);
}
}
}
What else might I have missed so that my GET
works perfectly from both the client and swagger, but the POST
only works from swagger, not the client?
We have a document for blazor application to send http request. Then I noticed that you have namespace BlazorAppDiscovery.Client.Services
which looks like you are working on a blazor web app interactive auto mode.
So that I created a blazor project like that, I added builder.Services.AddHttpClient();
in the Program.cs of the blazorapp instead of the blazorapp.Client. And in Counter.razor component in blazorapp.Client project, I have codes below and it worked well.
@rendermode InteractiveAuto
@inject HttpClient HttpClient
@code {
private int currentCount = 0;
private async Task IncrementCount()
{
currentCount++;
var model = new LocationModel
{
Location_NUM = 1,
Location_OWNER = "test"
};
var responseMesg = await HttpClient.PostAsJsonAsync("https://localhost:7245/api/Test", model);
var res = await responseMesg.Content.ReadAsStringAsync();
}
public class LocationModel
{
public int Location_NUM { get; set; }
public string Location_OWNER { get; set; }
}
}
And this is my API.
[HttpPost]
public int Add(LocationModel newLocation)
{
string strSQL = @"INSERT INTO dbo.Location(Location_NUM, Location_OWNER)
VALUES(@Location_NUM, @Location_OWNER);";
//using IDbConnection connection = new SqlConnection(connectionString);
//{
// return connection.Execute(strSQL, newLocation);
//}
return 1;
}
Based on the return error:
'400 Bad Request'. {StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers: { Date: Fri, 03 Jan 2025 01:04:33 GMT Server: Kestrel Transfer-Encoding: chunked Content-Type: application/problem+json; charset=utf-8 }}
To quote [from developer.mozilla.org]:
The HTTP 400 Bad Request client error response status code indicates that the server would not process the request due to something the server considered to be a client error. The reason for a 400 response is typically due to malformed request syntax, invalid request message framing, or deceptive request routing.
On the assumption the endpoint is correct, the likely reason for this is an invalid submitted Json object. You need to check the validity of your submitted LocationModel
. Are you handling nulls correctly?
The Bad Request error means something is wrong with the request syntax. It probably is a missing [FromBody]
:
[HttpPost]
//public int Add(LocationModel newLocation)
public int Add([FromBody] LocationModel newLocation)
{
...
}
If this doesn't help then post the exact Model class, it could be a nullability problem.
InsertLocationAsync
hit the Controller code?await http.PostAsJsonAsync(requestUri, newLocation)
returns aHttpResponseMessage
. What does it tell you? – MrC aka Shaun Curtis Commented Jan 2 at 22:26{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers: { Date: Fri, 03 Jan 2025 01:04:33 GMT Server: Kestrel Transfer-Encoding: chunked Content-Type: application/problem+json; charset=utf-8 }}
– John Marquez Commented Jan 3 at 1:07baseaddress + "api/Locations/";
Change it to just"api/Locations/";
because, according to the docs "When sending aHttpRequestMessage
with a relative Uri, the message Uri will be added to theBaseAddress
property to create an absolute Uri. Note that all characters after the right-most "/" in the base URI are excluded when combined with the message URI". If that doesn't solve the problem, I hope that helps a bit. – benjamin Commented Jan 3 at 5:36newLocation
and the request content including url of variablerequestUri
. – Tiny Wang Commented Jan 3 at 7:36