Consuming a Web API in Xamarin - c#

I've created a Web API in ASP.NET that is hosted on a web server. This Web API accesses a table in SQL Server where I have a table called Products with Id, ProductName, Description and Price, I did the tests via Postman and it is working correctly, but when I try to consume the method to bring a specific product via Xamarin application, I get the following error message in break mode:
System.Net.Http.HttpRequestException: Timeout exceeded getting exception details
public class DataService
{
public async Task<List<Product>> GetProductAsync(string ProductName)
{
using (var client = new HttpClient())
{
string url = "http://ProductsAPI.hostname.com/api";
try
{
var uri = url + "/" + ProductName.ToString();
HttpResponseMessage response = await client.GetAsync(uri);
var ProductJsonString = awaitresponse.Content.ReadAsStringAsync();
var Product = JsonConvert.DeserializeObject<List<Product>>(ProductJsonString);
return Product;
}
catch (Exception ex)
{
throw ex;
}
}
}
}

Here's what I've used in the past:
public string GetAPIJsonAsync(string URL)
{
using (WebClient wc = new WebClient())
{
return wc.DownloadString(URL);
}
}
This would return the raw JSON to whoever called it, and I would then convert it to the desirable object.

If you increase the timeout of the HttpClient, does it return more information?
Also, try Refit It does all the work for you, including deserializing into json.

This Works Perfectly for me
public static async Task<List<BranchMasterModel>> GetBranchList(int city)
{
var client = new HttpClient(new NativeMessageHandler());
client.BaseAddress = new Uri(UrlAdd);//("http://192.168.101.119:8475/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "AuthToken"));
var result = await client.GetAsync("api/Master/V2/Branch/"+city);
string branch = await result.Content.ReadAsStringAsync();
var branches = JsonConvert.DeserializeObject<List<BranchMasterModel>>(branch);
return branches;
}

Related

ASP.Net MVC auto slugify Routes

i have this code in my Controller:
string APIBaseurl = "https://sub.domain.de/";
[Route("VerseExkurs/Technologien/{technologie}")]
public async Task<ActionResult> Details(string technologie)
{
TechnologieRootobject TechnologieInfo = new TechnologieRootobject();
using (var client = new HttpClient())
{
//Passing service base url
client.BaseAddress = new Uri(APIBaseurl);
client.DefaultRequestHeaders.Clear();
//Define request data format
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Sending request to find web api REST service resource GetAllEmployees using HttpClient
HttpResponseMessage Res = await client.GetAsync("items/technologien/" + technologie + "?access_token=token");
//Checking the response is successful or not which is sent using HttpClient
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var TechnologieResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
TechnologieInfo = JsonConvert.DeserializeObject<TechnologieRootobject>(TechnologieResponse);
}
//returning the employee list to view
return View(TechnologieInfo.data);
}
}
But the Problem is, the "{technologie}" Variable is in some Cases with Spaces. Is there any way to automatically convert spaces in underdashes?
You have few options.
Utilize string.Replace() method
HttpResponseMessage Res = await client.GetAsync("items/technologien/" + technologie.Replace(" ", "_") + "?access_token=token");
Write a helper function that returns correct string
string removeSpaceFromString(string inputString)
{
return inputString.Replace(" ", "_"); // or some other method of doing that
}

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.

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");
}
}
}

using shopify api with .net post requests on a private app

has anybody got a . net example of running a simple post to the shopify create order Ive seen some really old examples but they dont seem to work the ones that do answer have no code examples im trying the following but just get bad request back, surely this should be simple?
private static async Task runShopifyAsyncCreateOrderJsonTask()
{
using (var handler = new HttpClientHandler { Credentials = GetCredential() })
using (var client = new HttpClient(handler))
{
client.BaseAddress = new Uri(baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string json = #"{'order': {'line_items': [{'variant_id': 720123393,'quantity': 1}]}}";
// HTTP post
HttpResponseMessage response = await client.PostAsJsonAsync("admin/orders.json", test);
if (response.IsSuccessStatusCode)
{
Uri uri = response.Headers.Location;
var results = await response.Content.ReadAsStringAsync();
}
}
}
I know this post is old but in case someone comes across it check out these classes:
ShopifyApi.cs, ShopifyClient.cs, Program.cs. It uses WebClient which might be a little easier to use but still gets the point across.
After some playing around I found this works:
string ShopPath = "/admin/api/2020-04/";
string shopifyAddProduct = "products.json";
string shopifyGetProductFmt = "products.json?title={0}";
string URL = String.Format("https://{0}.myshopify.com{1}", ShopName, ShopPath);
var clientHandler = new HttpClientHandler
{
Credentials = new NetworkCredential(APIkey/*username*/, APIpass/*Password*/),
PreAuthenticate = true
};
HttpClient client = new HttpClient(clientHandler);
client.BaseAddress = new Uri(URL);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// need an access token...
client.DefaultRequestHeaders.Add("X-Shopify-Access-Token", APIpass);
var shopify = new
{
product = new
{
title = "Burton Custom Freestyle 151",
body_html = "<strong>Good snowboard!</strong>",
vendor = "Snowboard",
product_type = "Snowboard",
published = false
}
};
// before we try and add a product, we should query if we already have it?
string shopifyGetProduct = String.Format(shopifyGetProductFmt, Uri.EscapeUriString(shopify.product.title));
HttpResponseMessage getResponse = client.GetAsync(shopifyGetProduct).Result; // Blocking call! Program will wait here until a response is received or a timeout occurs.
if (getResponse.IsSuccessStatusCode)
{
bool foundProduct;
foundProduct = false;
// Parse the response body.
GetProducts curProduct = getResponse.Content.ReadAsAsync<GetProducts>().Result; //Make sure to add a reference to System.Net.Http.Formatting.dll
if (curProduct != null)
{
foreach (var cp in curProduct.products)
{
Console.WriteLine("found id: {0}", cp.id);
foundProduct = true;
}
}
if (!foundProduct)
{
HttpResponseMessage response = client.PostAsJsonAsync(shopifyAddProduct, shopify).Result; // Blocking call! Program will wait here until a response is received or a timeout occurs.
if (response.IsSuccessStatusCode)
{
// Parse the response body.
AddProducts newProduct = response.Content.ReadAsAsync<AddProducts>().Result; //Make sure to add a reference to System.Net.Http.Formatting.dll
if ((newProduct != null) && (newProduct.product != null))
{
Console.WriteLine("new id: {0}", newProduct.product.id);
}
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
}
else
{
Console.WriteLine("{0} ({1})", (int)getResponse.StatusCode, getResponse.ReasonPhrase);
}
//Dispose once all HttpClient calls are complete. This is not necessary if the containing object will be disposed of; for example in this case the HttpClient instance will be disposed automatically when the application terminates so the following call is superfluous.
client.Dispose();
No the code is not really asynchronous - I'll leave that to you to work out - I'm demonstrating how to use HttpClient with Shopify, not demonstrating how to write asynchronous code.
The AddProduct class can be generated by pasting the returned JSON into visual studio with 'paste special'. However the 'Root' classes are a bit difficult, so I'll paste them here:
public class AddProducts
{
public Product product { get; set; }
}
public class GetProducts
{
public Product[] products { get; set; }
}
Good luck!

Receiving JSON data back from HTTP request

I have a web request that is working properly, but it is just returning the status OK, but I need the object I am asking for it to return. I am not sure how to get the json value I am requesting. I am new to using the object HttpClient, is there a property I am missing out on? I really need the returning object. Thanks for any help
Making the call - runs fine returns the status OK.
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseMsg = client.GetAsync(string.Format("http://localhost:5057/api/Photo")).Result;
The api get method
//Cut out alot of code but you get the idea
public string Get()
{
return JsonConvert.SerializeObject(returnedPhoto);
}
If you are referring to the System.Net.HttpClient in .NET 4.5, you can get the content returned by GetAsync using the HttpResponseMessage.Content property as an HttpContent-derived object. You can then read the contents to a string using the HttpContent.ReadAsStringAsync method or as a stream using the ReadAsStreamAsync method.
The HttpClient class documentation includes this example:
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Building on #Panagiotis Kanavos' answer, here's a working method as example which will also return the response as an object instead of a string:
using System.Text;
using System.Net.Http;
using System.Threading.Tasks;
using Newtonsoft.Json; // Nuget Package
public static async Task<object> PostCallAPI(string url, object jsonObject)
{
try
{
using (HttpClient client = new HttpClient())
{
var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
var response = await client.PostAsync(url, content);
if (response != null)
{
var jsonString = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<object>(jsonString);
}
}
}
catch (Exception ex)
{
myCustomLogger.LogException(ex);
}
return null;
}
Keep in mind that this is only an example and that you'd probably would like to use HttpClient as a shared instance instead of using it in a using-clause.
Install this nuget package from Microsoft System.Net.Http.Json. It contains extension methods.
Then add using System.Net.Http.Json
Now, you'll be able to see these methods:
So you can now do this:
await httpClient.GetFromJsonAsync<IList<WeatherForecast>>("weatherforecast");
Source: https://www.stevejgordon.co.uk/sending-and-receiving-json-using-httpclient-with-system-net-http-json
I think the shortest way is:
var client = new HttpClient();
string reqUrl = $"http://myhost.mydomain.com/api/products/{ProdId}";
var prodResp = await client.GetAsync(reqUrl);
if (!prodResp.IsSuccessStatusCode){
FailRequirement();
}
var prods = await prodResp.Content.ReadAsAsync<Products>();
What I normally do, similar to answer one:
var response = await httpClient.GetAsync(completeURL); // http://192.168.0.1:915/api/Controller/Object
if (response.IsSuccessStatusCode == true)
{
string res = await response.Content.ReadAsStringAsync();
var content = Json.Deserialize<Model>(res);
// do whatever you need with the JSON which is in 'content'
// ex: int id = content.Id;
Navigate();
return true;
}
else
{
await JSRuntime.Current.InvokeAsync<string>("alert", "Warning, the credentials you have entered are incorrect.");
return false;
}
Where 'model' is your C# model class.
It's working fine for me by the following way -
public async Task<object> TestMethod(TestModel model)
{
try
{
var apicallObject = new
{
Id= model.Id,
name= model.Name
};
if (apicallObject != null)
{
var bodyContent = JsonConvert.SerializeObject(apicallObject);
using (HttpClient client = new HttpClient())
{
var content = new StringContent(bodyContent.ToString(), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
client.DefaultRequestHeaders.Add("access-token", _token); // _token = access token
var response = await client.PostAsync(_url, content); // _url =api endpoint url
if (response != null)
{
var jsonString = await response.Content.ReadAsStringAsync();
try
{
var result = JsonConvert.DeserializeObject<TestModel2>(jsonString); // TestModel2 = deserialize object
}
catch (Exception e){
//msg
throw e;
}
}
}
}
}
catch (Exception ex)
{
throw ex;
}
return null;
}
The code below is to access your HttpResponseMessage and extract your response from HttpContent.
string result = ret.Result.Content.ReadAsStringAsync().Result;
Convert your json in a structure according with your business
In my case BatchPDF is a complex object that it is being populated by result variable.
BatchPDF batchJson = JsonConvert.DeserializeObject<BatchPDF>(result);
return batchJson;

Categories