Home > database >  Why GetFromJsonAsync can't parse the JSON but ReadFromJsonAsync can parse the same JSON respons
Why GetFromJsonAsync can't parse the JSON but ReadFromJsonAsync can parse the same JSON respons

Time:06-28

I'm using HttpClient to send requests to my API project, the problem is that the GetFromJsonAsync method fails to parse the response JSON, but if I first get the response using the GetAsync method, and then do a ReadFromJsonAsync on that, it'll parse the JSON successfully, why is that?

This code doesn't work:

public async Task<OperationResult<LoginNextStep>> SearchByEmailOrPhone(string emailOrPhone)
{
    // This fails to parse the response body
    var result = await _client.GetFromJsonAsync<ApiResult<OperationResult<LoginNextStep>>>
        ($"api/user/searchbyemailorphone/{emailOrPhone}", _jsonOptions);
    
    return result.Data;
}

This one does:

public async Task<OperationResult<LoginNextStep>> SearchByEmailOrPhone(string emailOrPhone)
{
    var result = await _client.GetAsync($"api/user/searchbyemailorphone/{emailOrPhone}");

    // But this one works, with the same JSON
    var jsonResult = await result.Content.ReadFromJsonAsync
        <ApiResult<OperationResult<LoginNextStep>>>(_jsonOptions);

    return jsonResult.Data;
}

This is the _jsonOptions passed into the methods (Injected through the constructor into the class):

services.AddSingleton(new JsonSerializerOptions
{
    Converters = { new JsonStringEnumConverter() },
    PropertyNameCaseInsensitive = true
});

EDIT:

I forgot to say this, this only happens with a specific JSON returned from the API, I mean it's the same type as ApiResutl but for some weird reasons it fails to parse it, and in my API project, I'm using the AspNetCoreRateLimit package to throttle the spam requests, and in that package, if it decides to drop a request, it would by default return a line of text, but I could overwrite that and I added my own return type when it drops a request, and it's an ApiResult which is the default return type of all of my API's endpoints, (so I wanted that package to return the same result as other endpoints with 429 status code to indicate TooManyRequests).

This is the overwritten return type when it drops a spam request:

public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware
{
    public CustomIpRateLimitMiddleware(RequestDelegate next, IProcessingStrategy processingStrategy,
        IOptions<IpRateLimitOptions> options, IIpPolicyStore policyStore, IRateLimitConfiguration config,
        ILogger<IpRateLimitMiddleware> logger) : base(next, processingStrategy, options, policyStore, config, logger)
    {
    }

    public override async Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitRule rule,
        string retryAfter)
    {
        var result = new ApiResult
        {
            IsSuccessful = false,
            MetaData = new MetaData
            {
                ApiStatusCode = ApiStatusCode.TooManyRequests,
                Message = "You sent too many requests!!!"
            }
        };

        var jsonOptions = new JsonSerializerOptions { Converters = { new JsonStringEnumConverter() } };
        var jsonResult = JsonSerializer.Serialize(result, jsonOptions);
        httpContext.Response.Headers["Retry-After"] = retryAfter;
        httpContext.Response.StatusCode = (int)ApiStatusCode.TooManyRequests;
        httpContext.Response.ContentType = "application/json";

        await httpContext.Response.WriteAsync(jsonResult);
        //return base.ReturnQuotaExceededResponse(httpContext, rule, retryAfter);
    }
}

To produce the issue, first I manually try to spam and the API will throttle my requests:

enter image description here

And then this is the response body as string, which is the same as the picture above:

enter image description here

The ReadFromJsonAsync could parse the JSON:

enter image description here

But the same request with GetFromJsonAsync fails, and it throws an HttpRequestException exception, (I think I did the same thing yesterday and it would throw an exception like CouldNotParseJson to ApiResult type

  • Related