How to Deserialize JSON into C# objects correctly?


I have a function that calls API requests, and I want to have each request return its own data type according to its purpose.
For that, I created a class called ApiResponse. Here is its code:

    public class ApiResponse<T>
    {
        public bool Success { get; set; }
        public string? ErrorMessage { get; set; }
        public T? Data { get; set; }

        public ApiResponse()
        {
            Success = true; // Default to success
        }
    }

The way I use this class is when I request DB queries, the data, which is of type T will be DBResponse. Here is its implementation:

    public class DBResponse<T>
    {
        public int Code { get; set; }
        public string Message { get; set; }
        public bool Success { get; set; }
        public T? Data { get; set; }

        public DBResponse(int code, string message, bool success, T? data = default)
        {
            Code = code;
            Message = message;
            Success = success;
            Data = data;
        }
    }

And, the method I created for calling the API requests is:

public async Task<ApiResponse<T>> SendRequestAsync<T>(string route, object? body = null)
{
    var appSettings = new AppSettings();
    try
    {
        // Prepare the request payload
        var requestPayload = new
        {
            Database = "my-database",
            Username = "my-user",
            Password = "my-password",
            Body = body
        };

        var content = new StringContent(JsonSerializer.Serialize(requestPayload), Encoding.UTF8, "application/json");

        // Call the API
        var response = await httpClient.PostAsync($"{appSettings.ApplicationUrl}/request/{route}", content);

        if (response.IsSuccessStatusCode)
        {
            // Get the raw response JSON as a string
            var rawResponseJson = await response.Content.ReadAsStringAsync();

            try
            {
                // Deserialize the raw response JSON into ApiResponse<T>
                var apiResponse = JsonSerializer.Deserialize<ApiResponse<T>>(rawResponseJson, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

                if (apiResponse == null)
                {
                    return new ApiResponse<T>
                    {
                        Success = false,
                        ErrorMessage = "No data returned from the API."
                    };
                }

                return apiResponse;
            }
            catch (Exception ex)
            {
                return new ApiResponse<T>
                {
                    Success = false,
                    ErrorMessage = $"Error deserializing response to type {typeof(T).Name}: {ex.Message}"
                };
            }
        }
        else
        {
            return new ApiResponse<T>
            {
                Success = false,
                ErrorMessage = $"HTTP Error: {response.StatusCode} - {response.ReasonPhrase}"
            };
        }
    }
    catch (Exception ex)
    {
        return new ApiResponse<T>
        {
            Success = false,
            ErrorMessage = $"SendRequestAsync general error: {ex.Message}"
        };
    }
}

I have one API request that fetches records from the database, hence its return type is ApiResponse<DBResponse<List<Dictionary<string, object>>>>. In this case, the function works well.
However, when I am doing an update, insert or delete SQL commands, the return type of the call is: ApiResponse<DBResponse<int>>.
In this case, I am getting an error on the command:

var apiResponse = JsonSerializer.Deserialize<ApiResponse<T>>(rawResponseJson, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });

Can someone please help me understand the problem I am having with the Deserialize call? Why can’t it convert simpler types from JSON?
I tried calling the Deserialize call without the PropertyNameCaseInsensitive = true, but that is worse.
Here is an example for JSON that works well:

{"success":true,"errorMessage":"","data":{"code":0,"message":"","success":true,"data":[{"Id":5,"Name":"One Value Updated Value Updated Value","CreatedOn":"2025-01-02T04:44:40"}]}}

And, here is an example for JSON that fails:

{"success":true,"errorMessage":"","data":{"code":0,"message":"Update successful.","success":true,"data":1}}

With this error message:

System.Text.Json.JsonException
  HResult=0x80131500
  Message=The JSON value could not be converted to Project.SharedLibrary.DBResponse`1[System.Int32]. Path: $.data.data | LineNumber: 0 | BytePositionInLine: 105.

Leave a Reply

Your email address will not be published. Required fields are marked *