0

I need help with returning multiple values from my api to the httpclient post request but its returning null

api

[HttpPost("ShowUser")]
    public (IEnumerable<UserInformation>, int) ShowUser([FromBody] Pagination pagination)
    { // retrieving data from database 
        var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
        Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
        {
            Data = result.Item1,
            RowsCount = result.Item2
        };
        return (paginationResponse.Data, paginationResponse.RowsCount);
    }

HttpClient Post Request

public async Task<(List<TOut>, TOut)> PostGetListRequest<TIn, TOut>(TIn content, string uri, string token)
    {
            ...

            using (response = await client.PostAsync(uri, serialized))
            {
                if (response.StatusCode.ToString() == "OK")
                {
                    responseBody =  response.Content.ReadAsStringAsync().Result;
                    var result = JsonConvert.DeserializeObject<(List<TOut>, TOut)>(responseBody);
                    return (result.Item1, result.Item2);
                }
                  ...
            }
    }

Output enter image description here

enter image description here

Any idea what's wrong with my code?

Basma
  • 31
  • 1
  • 1
  • 8

3 Answers3

1

Try changing your API code to this.

    [HttpPost("ShowUser")]
    public ActionResult ShowUser([FromBody] Pagination pagination)
    { // retrieving data from database 
        var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
        Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
        {
            Data = result.Item1,
            RowsCount = result.Item2
        };
        return Ok((paginationResponse.Data, paginationResponse.RowsCount));
    }

If this is is designed to be an API that others will consume, you really shouldn't be returning anonymous objects. I think it would be a better idea to either return a wrapper model, or simply return the pagingResponse model you already have.

    [HttpPost("ShowUser")]
    [ProducesResponseType(typeof(Entities.PaginationResponse<IEnumerable<UserInformation>>), StatusCodes.Status200OK)]
    public ActionResult ShowUser([FromBody] Pagination pagination)
    { // retrieving data from database 
        var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
        Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
        {
            Data = result.Item1,
            RowsCount = result.Item2
        };
        return Ok(paginationResponse);
    }

Let me know if this doesn't work or if you need anything else.

Happy coding!

Geoffrey Fook
  • 578
  • 3
  • 11
  • Thank you for helping me, I tried ur solution it worked but I don't know if there is a way to deserialize two object (data, rowcount) – Basma May 10 '22 at 07:11
  • 1
    Hi there. I'm glad it solved your issue. Short answer is no, it's considered bad practice. As I said, the correct approach is to either return the paginationResponse or create a wrapper model. Keep it simple. :) If you really want to return a tuple, you will need to create a custom converter on your API - which would essentially just result in you returning a wrapper model anyway. If you really want to go with this approach, you can read through this example. [json converter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm?msclkid=78100406d03b11eca5b679e3384e775b) – Geoffrey Fook May 10 '22 at 08:35
0

1-you should await for reading response content

                    responseBody =  await response.Content.ReadAsStringAsync();
2-Make Sure the response in not empty.

3- i discourage using tuples as it violates the Object orinted and clean code practices

Mohamed Elhakim
  • 204
  • 1
  • 3
  • 7
0
  1. For the empty response body, if your project version is beyond ASP.NET Core 3.x, be sure add NewtonSoft support, check detailed steps in this answer

    services.AddControllers()
        .AddNewtonsoftJson();
    
  2. Assume that the PostGetListRequest<TIn, TOut> method is invoked by using the following code, TOut is type of UserInformation class:

    await GetListRequest<string, UserInformation>("xxx", "https://localhost:portNumber/xxx", "xxx");
    

    So the deserialize type should be (List<UserInformation>, UserInformation).

    var result = JsonConvert.DeserializeObject<(List<TOut>, TOut)>(responseBody);
    

    But your API's return type is (IEnumerable<UserInformation>, int).

    public (IEnumerable<UserInformation>, int) ShowUser([FromBody] Pagination pagination)
    

    API's return type does not match the deserialize type. So you cannot deserialize successfully.

A working demo:

public async Task<(List<TOut>, int)> GetListRequest<TIn, TOut>(TIn content, string uri, string token)
{
    HttpClient client = new HttpClient();
    var response = await client.PostAsync(uri,serialized);
            
    var responseBody = response.Content.ReadAsStringAsync().Result;
    var result = JsonConvert.DeserializeObject<(List<TOut>, int)>(responseBody);
    return (result.Item1, result.Item2);
}

Api:

[HttpPost("ShowUser")]
public (IEnumerable<UserInformation>, int) ShowUser([FromBody] Pagination pagination)
{ // retrieving data from database 
    var result = _showUsers.ShowManagerUsers(pagination.PageSize, pagination.skip, pagination.searchValue); // the output here is({System.Collections.Generic.List<Entities.UserInformation>}, 37) (note: 37 is the rows total)
    Entities.PaginationResponse<IEnumerable<UserInformation>> paginationResponse = new Entities.PaginationResponse<IEnumerable<UserInformation>>
    {
        Data = result.Item1,
        RowsCount = result.Item2
    };
    return (paginationResponse.Data, paginationResponse.RowsCount);
}

Result:

enter image description here

enter image description here

Rena
  • 30,832
  • 6
  • 37
  • 72
  • Thank u @Rena for helping my but I'm still getting a null result – Basma May 10 '22 at 07:08
  • Hi, are you sure your api actually return data? Do you debug your code? – Rena May 10 '22 at 08:18
  • I tested my api in Postman its returning null I don't know why – Basma May 10 '22 at 08:24
  • Hi, you need set breakpoint to your api and debug it step by step to check which line does not contain value... Especially check the `result` in the `ShowUser` method. BTW, does the frombody parameter `Pagination pagination` receives the value? – Rena May 10 '22 at 08:27
  • yes pagination receives values, and result output is (the list and the count) but api return null – Basma May 10 '22 at 08:31
  • Hi, How is your `paginationResponse`? Do you check its value? – Rena May 10 '22 at 08:32