Consuming WEB API using HttpClient in c# console application

12,985

The code needs quite a bit of work.

The line you highlighted will always be empty because that's where you initialise the variable. What you want is run thorugh the code until you get the result back form the call.

First, make sure your api actually works, you can call the GET method you want in the browser and you see results.

 using (var client = new HttpClient())
 {
      var result = await client.GetAsync("bla");
      return await result.Content.ReadAsStringAsync();
 } 

that's an example of course, so replace that with your particular data and methods.

now, when you check the results just because your response.IsSuccessStatusCode is false that doesn't mean there are no records. What it means is that the call failed completely. Success result with an empty list is not the same thing as complete failure.

If you want to see what you get back you can alter your code a little bit:

if(response.IsSuccessStatusCode)
        {
            var responseData = await response.Content.ReadAsStringAsync();
            //more stuff
        }

put a breakpoint on this line and see what you actually get back, then you worry about casting the result to your list of objects. Just make sure you get back the same thing you get when you test the call in the browser.

<-------------------------------> More details after edit.

Why don't you simplify your code a little bit.

for example just set the URL of the request in one go :

 using (var client = new HttpClient())
            {
                var result = await client.GetAsync("http://localhost:2813/api/metersinfo");
                var response = await result.Content.ReadAsStringAsync();
                 //set debug point here and check to see if you get the correct data in the response object
            }

Your first order of the day is to see if you can hit the url and get the data. You can worry about the base address once you get a correct response. Start simple and work your way up from there, once you have a working sample.

<----------------- new edit ----------------> Ok, now that you are getting a response back, you can serialise the string back to the list of objects using something like Newtonsoft.Json. This is a NuGet package, you might either have it already installed, if not just add it.

Add a using statement at the top of the file.

using Newtonsoft.Json;

then your code becomes something like :

using (var client = new HttpClient())
 {
      var result = await client.GetAsync("bla");
      var response = await result.Content.ReadAsStringAsync();
      var mID = JsonConvert.DeserializeObject<List<meters_info_dev>>(response);
 } 

At this point you should have your list of objects and you can do whatever else you need.

Share:
12,985
Moeez
Author by

Moeez

Updated on June 13, 2022

Comments

  • Moeez
    Moeez almost 2 years

    I have created a web API in visual studio 2015 using a MySQL database. The API is working perfect.

    So I decided to make a console client application in which I can consume my web-service (web API). The client code is based on HttpClient, and in the API I have used HttpResponse. Now when I run my console application code, I get nothing. Below is my code:

    Class

    class meters_info_dev
    {
        public int id { get; set; }
        public string meter_msn { get; set; }
        public string meter_kwh { get; set; }
    }
    

    This class is same as in my web API model class:

    Model in web API

    namespace WebServiceMySQL.Models
    {
    
    using System;
    using System.Collections.Generic;
    
    public partial class meters_info_dev
    {
        public int id { get; set; }
        public string meter_msn { get; set; }
        public string meter_kwh { get; set; }
    }
    

    Console application code

    static HttpClient client = new HttpClient();
    
    static void ShowAllProducts(meters_info_dev mi)
    {
        Console.WriteLine($"Meter Serial Number:{mi.meter_msn}\t Meter_kwh: {mi.meter_kwh}", "\n");
    }
    
    static async Task<List<meters_info_dev>> GetAllRecordsAsync(string path)
    {
        List<meters_info_dev> mID = new List<meters_info_dev>();
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.IsSuccessStatusCode)
        {
            mID = await response.Content.ReadAsAsync<List<meters_info_dev>>();
        }
        else
        {
            Console.WriteLine("No Record Found");
        }
        return mID;
    }
    
    static void Main()
    {
        RunAsync().Wait();
    }
    
    static async Task RunAsync()
    {
        client.BaseAddress = new Uri("http://localhost:2813/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
        var m = await GetAllRecordsAsync("api/metersinfo/");
    
        foreach(var b in m)
        {
            ShowAllProducts(b);
        }
    }
    

    In my API I have 3 GET methods under a single controller, so I have created different routes for them. Also the URL for them is different.

    1. http://localhost:2813/api/metersinfo/ will return all records

    While debugging the code, I found that List<meters_info_dev> mID = new List<meters_info_dev>(); is empty:

    enter image description here

    While the response is 302 Found, the URL is also correct:

    enter image description here

    Update 1

    After a suggestion I have done the following:

    using (var client = new HttpClient())
    {
        List<meters_info_dev> mID = new List<meters_info_dev>();
        HttpResponseMessage response = await client.GetAsync(path);
        if (response.IsSuccessStatusCode)
        {
            mID = await response.Content.ReadAsAsync<List<meters_info_dev>>();
        }
        else
        {
            Console.WriteLine("No Record Found");
        }
       return mID;
    }
    

    When I run the application, I get the exception "An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set."

    Update 2

    I have added a new piece of code:

    using (var cl = new HttpClient())
    {
        var res = await cl.GetAsync("http://localhost:2813/api/metersinfo");
        var resp = await res.Content.ReadAsStringAsync();
    }
    

    And in the response I am getting all the records:

    enter image description here

    I don't know why it's not working with the other logic and what the problem is. I have also read the questions Httpclient consume web api via console app C# and Consuming Api in Console Application.

    Any help would be highly appreciated.

    • astef
      astef over 6 years
      On your first screenshot you're staying right after mID list initialization. So, it's no way how it can be populated. Place a breakpoint to a return mID; statement and check again.
    • Moeez
      Moeez over 6 years
      @astef The count is zero (0) on return mID
  • Moeez
    Moeez over 6 years
    I have worked on your suggestion. Kindly see my updated code
  • Andrei Dragotoniu
    Andrei Dragotoniu over 6 years
    added another suggestion related to the URL of the request
  • David Osborne
    David Osborne over 6 years
    Not sure about this: 'From a best practices point of view you want to use an HttpClient inside a using statement...' See: aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
  • Andrei Dragotoniu
    Andrei Dragotoniu over 6 years
    fair point, we can alter the code to take that into consideration. It would still be good to see if we can hit the URL and get some data first though
  • Moeez
    Moeez over 6 years
    @AndreiDragotoniu Kindly check my updated question. I have added a new piece of code suggested by you
  • Andrei Dragotoniu
    Andrei Dragotoniu over 6 years
    added code to my answer to deserialise the string response into your list of objects.
  • Henk Holterman
    Henk Holterman over 6 years
    Please edit/remove that part about using (new HttpClient()) being a best practice.
  • Moeez
    Moeez over 6 years
    @AndreiDragotoniu, well it works only when I want to get all records, I have another GET methods also that gives record by ID and Serial Number. And this method is not suitable for them. I needed a solution for my current logic as I have already tried it some where else, and obviously I don't know why it's not working here. But anyways, you helped me a lot. +1 for it