Calling ASP.NET WebAPI using HttpClient - c#

I am trying to grab some values from my web api using HttpClient. I managed to get a true status. However, I do not know how to grab values/read the JSON document. May I know if there's a way to do it?
I am currently doing in Xamarin.Forms in Visual Studio.
This is my code.
When I enter this URL into my browser, the document reads like this
{"d":[{"__type":"Info:#website.Model","infoClosingHours":"06:00:00 PM","infoID":1,"infoOpeningDays":"Monday","infoOpeningHours":"09:00:00 AM","infoStatus":"Open"}]}
xaml file
<Button Text="Grab Value" Clicked="GetData"/>
xaml.cs file
private void GetData(object sender, EventArgs e)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("ipaddress");
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
try{
HttpResponseMessage response = client.GetAsync("WebServices/information.svc/GetInformationJSON").Result;
HttpResponseMessage response1 = client.GetAsync("WebServices/information.svc/GetInformationJSON").Result;
}
catch
{
}
}

I recommend using a static HttpClient if you will have any kind of decent load on your app. Otherwise, you can experience port exhaustion and bring the server to its knees. See my response on using instance-based vs. static HttpClients - What is the overhead of creating a new HttpClient per call in a WebAPI client?

You could use it like this:
private async void GetData(object sender, EventArgs e)
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("ipaddress");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = client.GetAsync("WebServices/information.svc/GetInformationJSON").Result;
if (response.IsSuccessStatusCode)
{
MyObject responseObject = response.Content.ReadAsAsync<MyObject>();
}
}
catch
{
}
}
}
For this to work you need to create a class "MyObject" that has the Properties from your JSON-Data.
It would also be possible to just deserialize it to a dynamic object like this:
private async void GetData(object sender, EventArgs e)
{
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("ipaddress");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
HttpResponseMessage response = client.GetAsync("WebServices/information.svc/GetInformationJSON").Result;
if (response.IsSuccessStatusCode)
{
string jsonString = await response.Content.ReadAsStringAsync();
dynamic dynamicObject = JsonConvert.DeserializeObject(jsonString);
}
}
catch
{
}
}
}
For this you would need the Newtonsoft.Json.

Related

HttpClient.GetAsync returns weird result for some websites

Please consider this simple Code:
private async void button3_Click(object sender, EventArgs e)
{
textBox1.Text = "It begins...";
await DoAsync_Button3();
}
private async Task DoAsync_Button3()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://www.stackoverflow.com/");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
textBox1.Text = responseBody;
}
and the simple UI:
the problem is for some websites I got some weird result. for example: https://www.dotnetperls.com/
I got this result:
I got weird result whereas StatusCode is 200. How do I determine where the problem is? Thanks
You need to decompress the response:
HttpClient httpClient = new HttpClient(new HttpClientHandler
{
AutomaticDecompression = System.Net.DecompressionMethods.All
});
string responseAsString = await httpClient.GetStringAsync("https://www.dotnetperls.com/");
Console.WriteLine(responseAsString);
If you are using .NET 5 or 6, you can use SocketsHttpHandler instead of HttpClientHandler.

PostAsync API giving Bad Gateway

I am invoking a third party POST API from my own API (again POST METHOD). The third party API is having a security key, and it is working fine on the POSTMAN tool. However, when I tries to invoke through code, I am getting error, 'Bad Gateway'. Following is the code which I tried.
public static async Task<string> GetDetailsfromThirdParty(string kszstrng)
{
string contentstring = string.Empty;
using (var client = new HttpClient())
{
string baseURL = "https://abcde.kz.in/b2/vhsearch-all";
string prms = kszstrng;// input parameters to API, in JSON Format- this is JSON String.
try
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Add("key", "value");
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
byte[] messageBytes = System.Text.Encoding.UTF8.GetBytes(prms);
var content = new ByteArrayContent(messageBytes);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
var response = await httpClient.PostAsync(baseURL, content).ConfigureAwait(false);
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
contentstring = result;
}
}
catch (Exception ex)
{
string msg = ex.Message.ToString();
}
return contentstring;
}
}
I am getting error on this line:
var response = await httpClient.PostAsync(baseURL, content).ConfigureAwait(false);
While trying to execute I am getting the below error:
Not able to find out what's the issue? There is no network / Fireawall blockage. I have cross-verified with Systems Team as well.
Please suggest any issue with the code.
First of all, i recommend you to not declare the HttpClient in a using statement since this can cause a socket exhaustion (because the connections will stay open).
(see the docs for details)
Go for a static HttpClient (or use the IHttpClientFactory if you're project is .net Core).
I can't test your code since I'm not able to access this api.
But give it a try using a cleaner approach:
// static HttpClient
private static readonly HttpClient _HttpClient = new HttpClient();
// Can be used to set the baseUrl of the HttpClient from outside
public static void SetBaseUrl(Uri baseUrl)
{
_HttpClient.BaseAddress = baseUrl;
}
public static async Task<string> GetDetailsfromThirdParty(string kszstrng)
{
string contentstring = string.Empty;
string baseURL = "https://abcde.kz.in/b2/vhsearch-all";
string prms = kszstrng; // input parameters to API, in JSON Format- this is JSON String.
try
{
// Be aware of which headers you wanna clean if using the static HttpClient
_HttpClient.DefaultRequestHeaders.Accept.Clear();
_HttpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_HttpClient.DefaultRequestHeaders.Add("key", "value");
_HttpClient.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
byte[] messageBytes = Encoding.UTF8.GetBytes(prms);
var content = new ByteArrayContent(messageBytes);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _HttpClient.PostAsync(baseURL, content).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
contentstring = result;
}
}
catch (Exception ex)
{
// your exception handling
}
return contentstring;
}
Issue resolved. While forming the object to JSON String, there was an opening and closing angle brackets ([,]). Even though this is coming automatically while converting to JSON string, this was not accepted string at the vendor end. So I removed it and works perfectly. Thanks every one for the support.

C# How to post data with multiple POST requests through Facebook API

I've been trying to post a message along with a link, I can send one POST request, but I am not sure how would one send two.
Here's my code:
private void Button2_Click(object sender, EventArgs e)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("https://graph.facebook.com");
string message = "hello";
string link = "www.facebook.com"
var payload = GetPayload(new {message});
HttpResponseMessage response2 = client.PostAsync($"me/feed?access_token={TextBox1.Text}", payload).Result;
}
}
private static StringContent GetPayload(object data)
{
var json = JsonConvert.SerializeObject(data);
return new StringContent(json, Encoding.UTF8, "application/json");
}
I am not sure how can I include the link too along with the message.
Al-right it turns out that the variable link should be passed as such:
var data = {message, link}
Thanks to chetan.

Xamarin Forms Post Request Http Issue

I'm working on making a POST request using my Xamarin form to send data to an Action in my controller in my WebAPI project. The code with breakpoints doesn't go beyond
client.BaseAddress = new Uri("192.168.79.119:10000");
I have namespace System.Net.Http and using System mentioned in the code.
private void BtnSubmitClicked(object sender, EventArgs eventArgs)
{
System.Threading.Tasks.Task<HttpResponseMessage> statCode = ResetPassword();
App.Log(string.Format("Status Code", statCode));
}
public async Task<HttpResponseMessage> ResetPassword()
{
ForgotPassword model = new ForgotPassword();
model.Email = Email.Text;
var client = new HttpClient();
client.BaseAddress = new Uri("192.168.79.119:10000");
var content = new StringContent(
JsonConvert.SerializeObject(new { Email = Email.Text }));
HttpResponseMessage response = await client.PostAsync("/api/api/Account/PasswordReset", content); //the Address is correct
return response;
}
Need a way to make a Post request to that Action and sending that String or the Model.Email as a parameter.
You need to use a proper Uri and also await the Task being returned from the called method.
private async void BtnSubmitClicked(object sender, EventArgs eventArgs) {
HttpResponseMessage response = await ResetPasswordAsync();
App.Log(string.Format("Status Code: {0}", response.StatusCode));
}
public Task<HttpResponseMessage> ResetPasswordAsync() {
var model = new ForgotPassword() {
Email = Email.Text
};
var client = new HttpClient();
client.BaseAddress = new Uri("http://192.168.79.119:10000");
var json = JsonConvert.SerializeObject(model);
var content = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
var path = "api/api/Account/PasswordReset";
return client.PostAsync(path, content); //the Address is correct
}

Testing REST API endpoints

I have a number of REST api endpoints that I am calling via ajax from a web client, and I want to write some automated tests to insure that they work properly outside of a web browser.
I am writing them as unit tests Tests and here is what I have so far:
[TestClass]
public class ApiTests
{
string local_host_address = "http://localhost:1234//";
public async Task<string> Post(string path, IEnumerable<KeyValuePair<string, string>> parameters)
{
using (var client = new HttpClient())
{
client.Timeout = new TimeSpan(0,0,5);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var response_message = await client.PostAsync(local_host_address + path, new FormUrlEncodedContent(parameters));
var response = await response_message.Content.ReadAsStringAsync();
if (response_message.IsSuccessStatusCode)
{
return response;
}
else
{
throw new Exception("Request failed");
}
}
}
[TestMethod]
[TestCategory("ApiTests")]
public void TestLogon()
{
var parameters = new Dictionary<string, string>();
parameters["email"] = "bob#aol.com";
parameters["password"] = "rosebud";
Task.Run( () =>
{
var output = Post("Default.aspx/Logon", parameters);
Console.WriteLine(output.Result);
}).Wait();
}
}
...pretty basic, it just tries to call a specific endpoint, and return the results. Problem is, this call returns the basic default.aspx web page body, not the results generated by default.aspx/logon. I am doing something wrong, but I have been over it with a debugger and I cannot see my error. The default.aspx/logon endpoint exists and it works perfectly when I access it via website. Am I missing or overlooking something?
-TTM
SOLUTION:
Bruno's alteration of my code snippet works quite nicely. Anyone else trying to solve the problem of testing a REST endpoint can just put that into a unit test and pass in a POCO and it will return the JSON response.
You are sending the body as FormUrlEncoded although you marked your request as application/json.
If your API is REST and takes JSON, instead of taking the Dictionary, you could deserialize an object (e.g. with Newtonsoft.Json):
public async Task<string> Post<T>(string path, T data)
{
using (var client = new HttpClient())
{
client.Timeout = new TimeSpan(0, 0, 5);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = JsonConvert.SerializeObject(data);
var response_message = await client.PostAsync(local_host_address + path, new StringContent(json, Encoding.UTF8, "application/json");
var response = await response_message.Content.ReadAsStringAsync();
if (response_message.IsSuccessStatusCode)
{
return response;
}
else
{
throw new Exception("Request failed");
}
}
}

Categories