Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

JSON string will not deserialize into the type specified

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":[]}

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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));
}

>Solution :

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);
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading