Monojit Sarkar Monojit Sarkar - 3 months ago 31
C# Question

How to read webapi responses with HttpClient in C#

I am fairly new to webapi and have developed a small webapi which has a few actions and returns my custom class called Response.

The
Response
class



public class Response
{
bool IsSuccess=false;
string Message;
object ResponseData;

public Response(bool status, string message, object data)
{
IsSuccess = status;
Message = message;
ResponseData = data;
}
}


My webapi with actions



[RoutePrefix("api/customer")]
public class CustomerController : ApiController
{
static readonly ICustomerRepository repository = new CustomerRepository();

[HttpGet, Route("GetAll")]
public Response GetAllCustomers()
{
return new Response(true, "SUCCESS", repository.GetAll());
}

[HttpGet, Route("GetByID/{customerID}")]
public Response GetCustomer(string customerID)
{
Customer customer = repository.Get(customerID);
if (customer == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return new Response(true, "SUCCESS", customer);
//return Request.CreateResponse(HttpStatusCode.OK, response);
}

[HttpGet, Route("GetByCountryName/{country}")]
public IEnumerable<Customer> GetCustomersByCountry(string country)
{
return repository.GetAll().Where(
c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
}
}


Now where I am stuck is that I do not know how to read the response data returned from the webapi actions and extract json from my response class. After getting json how could I
deserialize
that json to the customer class.

This is the way i am calling my webapi function:

private void btnLoad_Click(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:8010/");
// Add an Accept header for JSON format.
//client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// List all Names.
HttpResponseMessage response = client.GetAsync("api/customer/GetAll").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
Console.WriteLine("Request Message Information:- \n\n" + response.RequestMessage + "\n");
Console.WriteLine("Response Message Header \n\n" + response.Content.Headers + "\n");
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
Console.ReadLine();
}


Please help me to sort out my code


1) How to get the response class the webapi returns at the client
side

2) How could I extract json from the response class

3) How to deserialize the json to the customer class at client side


Thanks

EDIT



I use this code but still getting an error.

var baseAddress = "http://localhost:8010/api/customer/GetAll";
using (var client = new HttpClient())
{
using (var response = client.GetAsync(baseAddress).Result)
{
if (response.IsSuccessStatusCode)
{
var customerJsonString = await response.Content.ReadAsStringAsync();
var cust = JsonConvert.DeserializeObject<Response>(customerJsonString);
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
}


The error msg is:


An exception of type 'Newtonsoft.Json.JsonSerializationException'
occurred in Newtonsoft.Json.dll but was not handled in user code

Additional information: Cannot deserialize the current JSON object
(e.g. {"name":"value"}) into type 'WebAPIClient.Response[]' because
the type requires a JSON array (e.g. [1,2,3]) to deserialize
correctly.


Why is the response causing this error?

Answer

On the client, include a read of the content:

    HttpResponseMessage response = client.GetAsync("api/customer/GetAll").Result;  // Blocking call!  
    if (response.IsSuccessStatusCode)
    {
        Console.WriteLine("Request Message Information:- \n\n" + response.RequestMessage + "\n");
        Console.WriteLine("Response Message Header \n\n" + response.Content.Headers + "\n");
        // Get the response
        var customerJsonString = await response.Content.ReadAsStringAsync();
        Console.WriteLine("Your response data is: " + customerJsonString);

        // Deserialise the data (include the Newtonsoft JSON Nuget package if you don't already have it)
        var deserialized = JsonConvert.DeserializeObject<IEnumerable<Customer>>(custome‌​rJsonString);
        // Do something with it
    }

Change your WebApi not to use your Response class but rather an IEnumerable of Customer. Use the HttpResponseMessage response class.

Your WebAPI should only require:

[HttpGet, Route("GetAll")]
public IEnumerable<Customer> GetAllCustomers()
{
    var allCustomers = repository.GetAll();
    // Set a breakpoint on the line below to confirm
    // you are getting data back from your repository.
    return allCustomers;
}

Added code for a generic response class based on the discussion in the comments although I still recommend you don't do this and avoid calling your class Response. You should rather return HTTP status codes instead of your own. A 200 Ok, a 401 Unauthorised, etc. Also this post on how to return HTTP status codes.

    public class Response<T>
    {
        public bool IsSuccess { get; set; }
        public string Message { get; set; }
        public IEnumerable<T> ResponseData { get; set; }

        public Response(bool status, string message, IEnumerable<T> data)
        {
            IsSuccess = status;
            Message = message;
            ResponseData = data;
        }
    }