I have the following bit of code whihc sends a Http POST request to the server. The server reurns a 400 Bad request response along with a error object in the form of Json:
namespace MyApp.Shared.Dtos.Response
{
public class ErrorItem
{
public string Message { get; set; }
public string Tag { get; set; }
}
public class ErrorDto
{
public string Title { get; set; }
public List<ErrorItem> Errors { get; set; } = new();
}
}
namespace Accounting.Web.Services
{
public interface IHttpService
{
Task<T> Get<T>(string uri);
Task<T> Post<T>(string uri, object value, bool addBearerToken = false);
public ErrorDto Error { get; set; }
}
public class HttpService: IHttpService
{
private HttpClient _httpClient;
public ErrorDto Error { get; set; }
public HttpService(HttpClient httpClient)
{
_httpClient = httpClient;
_stateService = stateService;
}
public async Task<T> Post<T>(string uri, object value)
{
var request = new HttpRequestMessage(HttpMethod.Post, uri);
request.Content = new StringContent(JsonSerializer.Serialize(value), Encoding.UTF8, "application/json");
return await sendRequest<T>(request, addBearerToken);
}
private async Task<T> sendRequest<T>(HttpRequestMessage request)
{
using var response = await _httpClient.SendAsync(request);
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
{
var result = await response.Content.ReadAsStringAsync();
Error = JsonSerializer.Deserialize<ErrorDto>(result);
//..
}
else
{
//..
}
}
}
}
The result correctly recieves the following response from the server as a JSON string:
{"title":"Username or password is incorrect","errors":[]}
And I can confirm by inspecting var result, it has the above value.
However, It doesn't seem deserialize into the ErrorDto class as one would expect it to: Error = JsonSerializer.Deserialize(result);
But I simply cannot see any problems with the code, it looks like it should be working.
*** UPDATE ***
My server API code returrns the JSOn using the same DTO class (It's a shared class) using the following code:
[HttpPost("authenticate")]
public ActionResult Authenticate(AuthenticateRequest loginRequest)
{
var auth = _userService.Authenticate(loginRequest);
ErrorDto error = new()
{
Title = "Username or password is incorrect"
};
if (auth.user == null || auth.token == null)
{
return BadRequest(error);
}
return Ok(auth.user.ConvertToDto(auth.token));
}
CodePudding user response:
By default System.Text.Json
is case-sensitive. There are multiple options to handle this, for example by providing corresponding JsonSerializerOptions
:
var json = @"{""title"":""Username or password is incorrect"",""errors"":[]}";
var errorDto = JsonSerializer.Deserialize<ErrorDto>(json, new JsonSerializerOptions
{
PropertyNameCaseInsensitive = true
});
Or marking properties with corresponding JsonPropertyNameAttribute
:
public class ErrorItem
{
[JsonPropertyName("message")]
public string Message { get; set; }
[JsonPropertyName("tag")]
public string Tag { get; set; }
}
public class ErrorDto
{
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("errors")]
public List<ErrorItem> Errors { get; set; } = new();
}
UPD
From How to customize property names and values with System.Text.Json doc:
Note
The web default is camel case.
If you want to switch from camel case to the naming policy used for DTOs you can do the following:
builder.Services.AddControllers()
.AddJsonOptions(opts => opts.JsonSerializerOptions.PropertyNamingPolicy = null);