Consuming WEB API using HttpClient in c# console application - c#

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.
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:
While the response is 302 Found, the URL is also correct:
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:
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.

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.

Related

Consuming Web API in Class library

I'm building plugin in auto-cad and using class library and web API with entity framework
But every time i try to consume web API in my class library the response returns with "Not Found".
This is my code of class library
[CommandMethod("Doit")]
public void Test()
{
Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
Checker c = new Checker() { WholeArea = 1000, BuildingArea = 200, Status = 1 };
using (var client = new HttpClient())
{
client.BaseAddress =new Uri("http://localhost:52133/api");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.PostAsJsonAsync("Checker", c).Result;
if (response.IsSuccessStatusCode)
{
ed.WriteMessage("Hello data");
}
else
{
ed.WriteMessage((response.StatusCode).ToString());
}
}
}
This my controller Post Method
// POST: api/Checkers
[ResponseType(typeof(Checker))]
public IHttpActionResult PostChecker(Checker checker)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Checkers.Add(checker);
db.SaveChanges();
return CreatedAtRoute("DefaultApi", new { id = checker.ID }, checker);
}
Firstly :Now i don not know what is the problem of that code to return not found
Second- If there is away to build plugins in auto-cad using .net core
Are you seeing a 404 response code?
Have you tried calling the api method from postman or fiddler?
I'd always try calling from one of those so you can be certain the api is responding correctly. This will tell you whether or not the issue lies in your consuming code.
I notice you're using PostAsJsonAsync to call the api method but the api method isn't marked as async, could that be the issue?
The api method also isn't decorated with the HttpPost attribute; I'm not sure if that's a requirement but I'd try each of these separately

HttpClient GetAsync not working as expected

When testing my web API with Postman my API get executes fine!
When it comes to running the code with HttpClient in my client application the code executes without error but without the expected result on the server.
What could be happening?
From my client application:
private string GetResponseFromURI(Uri u)
{
var response = "";
HttpResponseMessage result;
using (var client = new HttpClient())
{
Task task = Task.Run(async () =>
{
result = await client.GetAsync(u);
if (result.IsSuccessStatusCode)
{
response = await result.Content.ReadAsStringAsync();
}
});
task.Wait();
}
return response;
}
Here is the API controller:
[Route("api/[controller]")]
public class CartsController : Controller
{
private readonly ICartRepository _cartRepo;
public CartsController(ICartRepository cartRepo)
{
_cartRepo = cartRepo;
}
[HttpGet]
public string GetTodays()
{
return _cartRepo.GetTodaysCarts();
}
[HttpGet]
[Route("Add")]
public string GetIncrement()
{
var cart = new CountedCarts();
_cartRepo.Add(cart);
return _cartRepo.GetTodaysCarts();
}
[HttpGet]
[Route("Remove")]
public string GetDecrement()
{
_cartRepo.RemoveLast();
return _cartRepo.GetTodaysCarts();
}
}
Note these API calls work as expected when called from Postman.
You shouldn't use await with client.GetAsync, It's managed by .Net platform, because you can only send one request at the time.
just use it like this
var response = client.GetAsync("URL").Result; // Blocking call!
if (response.IsSuccessStatusCode)
{
// Parse the response body. Blocking!
var dataObjects = response.Content.ReadAsAsync<object>().Result;
}
else
{
var result = $"{(int)response.StatusCode} ({response.ReasonPhrase})";
// logger.WriteEntry(result, EventLogEntryType.Error, 40);
}
You are doing fire-and-forget approach. In your case, you need to wait for the result.
For example,
static async Task<string> GetResponseFromURI(Uri u)
{
var response = "";
using (var client = new HttpClient())
{
HttpResponseMessage result = await client.GetAsync(u);
if (result.IsSuccessStatusCode)
{
response = await result.Content.ReadAsStringAsync();
}
}
return response;
}
static void Main(string[] args)
{
var t = Task.Run(() => GetResponseFromURI(new Uri("http://www.google.com")));
t.Wait();
Console.WriteLine(t.Result);
Console.ReadLine();
}
Simple sample used to get page data.
public string GetPage(string url)
{
HttpResponseMessage response = client.GetAsync(url).Result;
if (response.IsSuccessStatusCode)
{
string page = response.Content.ReadAsStringAsync().Result;
return "Successfully load page";
}
else
{
return "Invalid Page url requested";
}
}
I've had a problem with chace control when using httpclient.
HttpBaseProtocalFilter^ filter = ref new HttpBaseProtocolFilter();
filter->CacheControl->ReadBehavior = Windows::Web::Http::Filters::HttpCacheReadBehavior::MostRecent;
HttpClient^ httpClient = ref new HttpClient(filter);
I'm not really sure what the expected results are or what results your getting at all so this is really just a guessing game right now.
When I POST something using HttpClient I found adding headers by hand seemed to work more often than using default headers.
auto httpClient = ref new HttpClient();
Windows::Web::Http::Headers::HttpMediaTypeHeaderValue^ type = ref new Windows::Web::http::Headers::HttpMediaTypeHeaderValue("application/json");
content->Headers->ContentType = type;
If I don't do these 2 things I found, for me anyways, that half the time my web requests were either not actually being sent or the headers were all messed up and the other half of the time it worked perfectly.
I just read a comment where you said it would only fire once, that makes me think it is the cachecontrol. I think what happens is something (Windows?) sees 2 requests being sent that are the exact same, so to speed things up it just assumes the same answer and never actually sends the request a 2nd time

Calling a GetAll method from a Web Api from your C# client

I was looking at examples online and found a tutorial on retrieving products that uses a C# WEB API service and a C# console application as the client however, the tutorial defines a function in the service to get all products however, it does not tell you how to call it from the client:
public IEnumerable<Product> GetAllProducts()
{
...
}
The other CRUD methods declare using IHttpActionResult so I was confused how to call it.
So in my client I blindly attempted to call doing the following which is obviously incorrect:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:59888/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET ALL
HttpResponseMessage response = await client.GetAsync("api/products");
if (response.IsSuccessStatusCode)
{
List<Model.Product> products = await.response.Content.ReadAsAsync<IEnumerable<Model.Product>();
}
}
This gives me a syntax error. So how do I code it them? Do I need to change the server or the client code or both?
For a single product the code is and this works:
// HTTP GET Specific Product
response = await client.GetAsync("api/products/1");
if (response.IsSuccessStatusCode)
{
Model.Product product = await response.Content.ReadAsAsync<Model.Product>();
}
and the server is:
public IHttpActionResult GetProduct(int id)
{
var product = repository.GetByID(id);
if (product != null)
return Ok(product);
else
return NotFound();
}
List<Model.Product> products = await.response.Content.ReadAsAsync<IEnumerable<Model.Product>();
You missed a closing > at the end. Correct:
var products = await.response.Content.ReadAsAsync<IEnumerable<Model.Product>>();

HttpClient hangs on request

I've been struggling with this for a couple of days.
C#, universal windows
I'm trying to access a device in my house that is web enabled. In looking at the API I should be able to make the following call:
{ "id" : "req-1", "url" : "/stable/av/", "method" : "browse" }
In fact, if I go into fiddler and send that to the device manually I get a response.
I'm using the following code:
try
{
using (var httpClient = new HttpClient { BaseAddress = baseAddress })
{
var _req = new SendRequest();
_req.id = "rec-100";
_req.url = "/stable/av/";
_req.method = "browse";
var _json = JsonConvert.SerializeObject(_req);
using (var content = new StringContent(_json.ToString(),Encoding.UTF8, "application/json"))
{
using (var response = await httpClient.PostAsync(baseAddress, content).ConfigureAwait(false))
{
responseData = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}
var _Response = JsonConvert.DeserializeObject<Response>(responseData);
var item = new ZoneInfo();
item.szIPAddress = szIPAddress;
item.szZoneName = _Response.result.item.title;
lstZones.Add(item);
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
The app hangs on the httpClient.PostAsync(...
In fiddler when it hits the line for the httpClient.PostAsync(... I see the properly formed request getting sent: (this is copied and pasted from fiddler) {"id":"rec-100","url":"/stable/av/","method":"browse"}
But then I've got messages like this which scroll like crazy (10 / second) until I stop the application.
{"resultId":"492bfa78-b778-4696-ad7c-c0f6a7733c6f","customData":"{\"type\":\"SamplePoints\",\"begin\":{\"h\":0,\"l\":0},\"end\":{\"h\":5,\"l\":-1002889776},\"samples\":436}","dwSessionId":"c533eca5-9ea7-4348-81bd-1920f8ee03da","dwRequestId":"e428bd3c-9d41-479c-993f-325fbfbb4adb"}
This is not the data I get when I post manually...
I'm not as concerned at the moment with the "hang", I'm more concerned about getting the correct data back.

Why Httpclient returns always the same result C# PCL?

I am using HttpClient PCL Class library. But When First Time I Get the JSON result It return correct data. After that HttpClient returns the same JSON result again and again for one URL till I close the application and start it again. My code looks like that
public class HttpService : IHttpService
{
public async Task<TResponseType> GetAsync<TResponseType>(string method, string parameters = null) where TResponseType : class
{
var uri = new Uri(string.Format(Constants.ServerUrl + method + parameters));
using (var client=new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic",
"c2Rzb2w6c2Rzb2w5OQ==");
var response = await client.GetAsync(uri);
var result = response.Content.ReadAsStringAsync().Result;
return JsonConvert.DeserializeObject<TResponseType>(result);
}
}
}
As stated in an answer for a different question, the solution is to set the IfModifiedSince property to prevent the default caching behaviour like this:
httpClient.DefaultRequestHeaders.IfModifiedSince = DateTime.Now;
You could also check on MSDN for more information.

Categories

Resources