c# API client using Desktop application - c#

I have to create a client application to connect to an API to post and get information,
the information that I got from the company who have the API is:
API details for: xxxxx
Integration: yyyyxxxx
API URL: https://api.xyz.us/v123/
APP KEY: xxxxx12312xxxxx2123123xxxxx
SECRET KEY: 11111111111111111xxxxxxxxxxx
I want to use c# or other language to create the client, I couldn't find any c# sample for desktop application, I found a c# console basic sample, It's like no one use APIs with c#,
Is there any sample for a client to connect to an API using C# Desktop application?
or what can I use to accomplish this task?
Thanks

Here's HttpClient example based on the snippet from OP's answer
using System.Threading.Tasks;
using System.Net.Http;
using System.Text;
using System.Net.Http.Headers;
public class RESTClient
{
private readonly HttpClient client = new HttpClient();
public RESTClient(string baseAddress)
{
client.BaseAddress = new Uri(baseAddress);
}
public void SetAuthHeader(string parameter)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", parameter);
}
public async Task<string> MakeRequestAsync(HttpMethod method, string path, string postContent = "")
{
try
{
using (HttpContent content = new StringContent(postContent, Encoding.UTF8, "application/json"))
using (HttpRequestMessage request = new HttpRequestMessage(method, path))
{
if (method == HttpMethod.Post || method == HttpMethod.Put) request.Content = content;
using (HttpResponseMessage response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
{
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync().ConfigureAwait(false);
}
}
}
catch (Exception ex)
{
return "{\"errorMessages\":[\"" + ex.Message + "\"],\"errors\":{}}";
}
}
}
Usage example (WinForms)
private RESTClient restClient;
private void Form1_Load(object sender, EventArgs e)
{
restClient = new RESTClient("https://myapi.url/api");
restClient.SetAuthHeader("iODA0NjMxMTgwMWUzYWFkYTk4NjM2MjcyOTk3MDowYTU0N2I2NzliNWRkMjliN2I4NTFlMDBkY2Y2NjQzNzQ5OTIxYzZl");
}
private async void button1_Click(object sender, EventArgs e)
{
// GET
string getJsonResult = await restClient.MakeRequestAsync(HttpMethod.Get, "path/to/method");
// POST
string postJsonResult = await restClient.MakeRequestAsync(HttpMethod.Post, "path/to/method", "{\"data\": \"Some Request Data\"}");
// process data here
}

Thanks to everyone who help. I found the answer on Postman,
first I found a C# desktop client application sample.
the problem with this sample is that it didn't use an API key and secret key.
I found many answers on how to add the API key and secret key
but the one worked was the one on Postman, in the section 'code'
request.Headers["Authorization"] = "Basic ZmRiODA0NjMxMTgwMWUzYWFkYTk4NjM2MjcyOTk3MDowYTU0N2I2NzliNWRkMjliN2I4NTFlMDBkY2Y2NjQzNzQ5OTIxYzZl";
the complete c# code is:
using System;
using System.IO;
using System.Net;
using System.Text;
namespace restClient_0
{
public enum httpVerb
{
GET,
POST,
PUT,
DELETE
}
class RESTClient
{
public string endPoint { get; set; }
public httpVerb httpMethod { get; set; }
public RESTClient()
{
endPoint = "";
httpMethod = httpVerb.GET;
}
public string makeRequest()
{
string strResponseValue = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(endPoint);
request.Method = httpMethod.ToString();
request.Headers["Authorization"] = "Basic iODA0NjMxMTgwMWUzYWFkYTk4NjM2MjcyOTk3MDowYTU0N2I2NzliNWRkMjliN2I4NTFlMDBkY2Y2NjQzNzQ5OTIxYzZl";
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)request.GetResponse();
//Proecess the resppnse stream... (could be JSON, XML or HTML etc..._
using (Stream responseStream = response.GetResponseStream())
{
if (responseStream != null)
{
using (StreamReader reader = new StreamReader(responseStream))
{
strResponseValue = reader.ReadToEnd();
}
}
}
}
catch(Exception ex)
{
strResponseValue = "{\"errorMessages\":[\"" + ex.Message.ToString() + "\"],\"errors\":{}}";
}
finally
{
if (response != null)
{
((IDisposable)response).Dispose();
}
}
return strResponseValue;
}
}
}

Related

API GET method doesn't store data in the property in Xamarin Forms

Data is being retrieve from the API succesfully, as I can see it here,
response
and then goes to the jsonstring, but never gets to the CantGet variable
I need it to be store in my property so I can use the value.
This is my API return:
[{"CantPremio":"70"}
Then this is my property:
using System;
using System.Collections.Generic;
using System.Text;
namespace ServLottery
{
public class GetCantPremio
{
public long CantPremio { get; set; }
}
}
This is the Get task
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
namespace ServLottery
{
public class RestClient
{
HttpClient client = new HttpClient();
public async Task<T> Get<T>(string URL)
{
try
{
var response = await client.GetAsync(URL);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var jsonstring = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonstring);
}
}
catch
{
}
return default(T);
}
}
}
Finally this is the call:
private async void GetCantDisponible()
{
try
{
RestClient client = new RestClient();
var CantGet = await client.Get<GetCantPremio>("https://servicentroapi.azurewebsites.net/api/GetNumber");
if (CantGet != null)
{
PremiosCantLocal = CantGet.CantPremio.ToString();
}
}
catch (Exception ex)
{
throw ex;
}
}
The api you are accessing is returning an array. So you must deserialize not a simple object but a list.
return Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonstring);
Replace the line that deserializes with this one. Should solve the problem
Like kelvin said, set the List<T> for the json array. And then foreach the collection to get the CantPremio.
RestClient:
public class RestClient
{
HttpClient client = new HttpClient();
public async Task<List<T>> Get<T>(string URL)
{
try
{
var response = await client.GetAsync(URL);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var jsonstring = await response.Content.ReadAsStringAsync();
var s = Newtonsoft.Json.JsonConvert.DeserializeObject<List<T>>(jsonstring);
return s;
}
}
catch
{
}
return default(List<T>);
}
}
GetCantDisponible:
private async void GetCantDisponible()
{
try
{
RestClient client = new RestClient();
var CantGet = await client.Get<GetCantPremio>("https://servicentroapi.azurewebsites.net/api/GetNumber");
if (CantGet != null)
{
foreach (var item in CantGet)
{
var PremiosCantLocal = item.CantPremio.ToString();
}
}
}
catch (Exception ex)
{
throw ex;
}
}
Screenshot:
As mentioned, your API is returning an array but you're trying to deserialize it to a single instance. I'd suggest changing the call site of your client to pass a list for the type parameter:
List<GetCantPremio> CantGet = await client.Get<List<GetCantPremio>>("https://servicentroapi.azurewebsites.net/api/GetNumber");
Note that CantGet is now a List. If you are only looking for one object you could just add on a FirstOrDefault():
GetCantPremio CantGet = await client.Get<List<GetCantPremio>>("https://servicentroapi.azurewebsites.net/api/GetNumber")?.FirstOrDefault();

404 error on using graph API from c# console app

I am currently trying to authenticate Graph API using my C#. I am able to query this API and receive the token successfully from Postman.But when I call same API, I get 404 error.
My code is as below:
using System;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace GraphTest
{
public class AuthenticationModel
{
public string grantType { get; set; } = "client_credentials";
public string clientId { get; set; } = "my_ad_app_id";
public string clientSecret { get; set; } = "client_secret";
public string scope { get; set; } = "https://graph.microsoft.com/.default";
}
public class Authentication
{
private static string tenantId = "tenant_id";
private static readonly HttpClient Client = new HttpClient();
public Authentication()
{
var authenticationModel = new AuthenticationModel();
RunAsync().GetAwaiter().GetResult();
}
private static async Task RunAsync()
{
Client.BaseAddress = new Uri("https://login.microsoftonline.com/");
Client.DefaultRequestHeaders.Accept.Clear();
Client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("*/*"));
Client.DefaultRequestHeaders.Add("Host", "login.microsoftonline.com");
Client.DefaultRequestHeaders.Add("Cache-Control", "no-cache");
try
{
var authenticationModel = new AuthenticationModel();
var url = await GetTokenAsync(authenticationModel);
Console.WriteLine($"Created at {url}");
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
private static async Task<Uri> GetTokenAsync(AuthenticationModel authenticationModel)
{
var keyValues = authenticationModel.GetType().GetProperties()
.ToList()
.Select(p => $"{p.Name} = {p.GetValue(authenticationModel)}")
.ToArray();
var xUrlEncodedBody = string.Join('&', keyValues);
var response = await Client.PostAsJsonAsync(
$"{tenantId}/oauth2/v2.0/token", xUrlEncodedBody);
response.EnsureSuccessStatusCode();
return response;
}
}
}
So, I recieve this in response: StatusCode:404, ReasonPhrase:Not Found
Please help me in knowing that where I am doing it wrong.
Note: API with same data works fine with Postman. Though, I have replaced some values here for security reasons.
You should not post form URL encoded content as JSON (PostAsJsonAsync). The body needs to have a content type of application/x-www-form-urlencoded.
But backing up a second, you don't need to implement the protocol yourself when there are libraries out there that do it for you :). We provide and support the Microsoft Authentication Library (MSAL) which makes this easy.
var app = ConfidentialClientApplicationBuilder.Create(config.ClientId)
.WithTenantId("{tenantID}")
.WithClientSecret(config.ClientSecret)
.Build();
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
AuthenticationResult result = null;
try
{
result = await app.AcquireTokenForClient(scopes).ExecuteAsync();
}
catch (MsalServiceException ex)
{
Console.WriteLine($"Error getting token: {ex.Message}");
}
Console.WriteLine($"Token: {result.AccessToken}");
I ran your code and it is wrongly generating query string as below with spaces.
xUrlEncodedBody => grantType = client_credentials&clientId = my_ad_app_id&clientSecret = client_secret&scope = https://graph.microsoft.com/.default
There is space between query parameter name and value, see below line.
.Select(p => $"{p.Name} = {p.GetValue(authenticationModel)}")
Remove the space and try again
.Select(p => $"{p.Name}={p.GetValue(authenticationModel)}")

Get JSON from url, save to file, and finally CreateActivationService

Using the Template Studio extension for Visual Studio, I generated a project solution base and am now attempting to interject the app load process with a HTTP request before proceeding the render the page view.
App.xaml.cs
using System;
using Braytech_3.Services;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Windows.UI.Xaml;
namespace Braytech_3
{
public sealed partial class App : Application
{
private Lazy<ActivationService> _activationService;
private ActivationService ActivationService
{
get { return _activationService.Value; }
}
public App()
{
InitializeComponent();
APIRequest();
// Deferred execution until used. Check https://msdn.microsoft.com/library/dd642331(v=vs.110).aspx for further info on Lazy<T> class.
_activationService = new Lazy<ActivationService>(CreateActivationService);
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
if (!args.PrelaunchActivated)
{
await ActivationService.ActivateAsync(args);
}
}
protected override async void OnActivated(IActivatedEventArgs args)
{
await ActivationService.ActivateAsync(args);
}
private async void APIRequest()
{
//Create an HTTP client object
Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient();
//Add a user-agent header to the GET request.
var headers = httpClient.DefaultRequestHeaders;
Uri requestUri = new Uri("https://json_url");
//Send the GET request asynchronously and retrieve the response as a string.
Windows.Web.Http.HttpResponseMessage httpResponse = new Windows.Web.Http.HttpResponseMessage();
string httpResponseBody = "";
try
{
//Send the GET request
httpResponse = await httpClient.GetAsync(requestUri);
httpResponse.EnsureSuccessStatusCode();
httpResponseBody = await httpResponse.Content.ReadAsStringAsync();
APITempSave(httpResponseBody);
}
catch (Exception ex)
{
}
}
private async void APITempSave(string json)
{
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
if (await tempFolder.TryGetItemAsync("APIData.json") != null)
{
StorageFile APIData = await tempFolder.GetFileAsync("APIData.json");
await FileIO.WriteTextAsync(APIData, json);
}
else
{
StorageFile APIData = await tempFolder.CreateFileAsync("APIData.json");
await FileIO.WriteTextAsync(APIData, json);
}
}
private ActivationService CreateActivationService()
{
return new ActivationService(this, typeof(Views.VendorsPage), new Lazy<UIElement>(CreateShell));
}
private UIElement CreateShell()
{
return new Views.ShellPage();
}
}
}
I think what I need to do is call _activationService = new Lazy<ActivationService>(CreateActivationService); once APITempSave() has been called but I am unsure of how to do so and what best practices are.
Any guidance would be greatly appreciated!
After further investigation and familiarisation with the generated solution, as well as additional Googling of await, async, and Tasks<>, I was able to implement the request as a service alongside items such as ThemeSelector, and ToastNotifications.
The ThemeSelector is one of the first things to be called in order to determine light and dark theme mode for the current user, so I was able to model my service around it and call it at the same time.
This is obviously very specific to the code that template studio generates, but some concepts are shared and should anyone else look for similar answers in the future maybe they'll find this.
APIRequest.cs (Service)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Storage;
namespace Braytech_3.Services
{
public static class APIRequest
{
internal static async Task Request()
{
//Create an HTTP client object
Windows.Web.Http.HttpClient httpClient = new Windows.Web.Http.HttpClient();
//Add a user-agent header to the GET request.
var headers = httpClient.DefaultRequestHeaders;
Uri requestUri = new Uri("https://json_url");
//Send the GET request asynchronously and retrieve the response as a string.
Windows.Web.Http.HttpResponseMessage httpResponse = new Windows.Web.Http.HttpResponseMessage();
string httpResponseBody = "";
try
{
//Send the GET request
httpResponse = await httpClient.GetAsync(requestUri);
httpResponse.EnsureSuccessStatusCode();
httpResponseBody = await httpResponse.Content.ReadAsStringAsync();
await APITempSave(httpResponseBody);
}
catch (Exception ex)
{
}
}
internal static async Task APITempSave(string json)
{
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
if (await tempFolder.TryGetItemAsync("APIData.json") != null)
{
StorageFile APIData = await tempFolder.GetFileAsync("APIData.json");
await FileIO.WriteTextAsync(APIData, json);
}
else
{
StorageFile APIData = await tempFolder.CreateFileAsync("APIData.json");
await FileIO.WriteTextAsync(APIData, json);
}
}
}
}
ActiviationService.cs (originally called by App.xaml.cs)
private async Task InitializeAsync()
{
await ThemeSelectorService.InitializeAsync();
await APIRequest.Request();
}

Cannot access API with correct username and password(c#-HttpClient)-Unauthorized Request

i am trying an api and receive data. i got the api username and password but when im trying to connect i get an unauthorized request. i thing something is wrong with my request-header -authentication.
here is my code:
using ApiData;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace GetDataFromApi
{
class Program
{
static void Main(string[] args)
{
string uri1 = "https://api.intrinio.com/companies?ticker=AAPL";
ConnectToApi newapi = new ConnectToApi("username", "password", uri1);
Console.ReadLine();
}
public class ConnectToApi
{
public string Username { get; set; }
public string Password { get; set; }
public string Request_url { get; set; }
public ConnectToApi(string username, string password, string url)
{
this.Username = username;
this.Password = password;
this.Request_url = url;
GetAPIToken(Username, Password, Request_url);
}
private static async void GetAPIToken(string userName, string password, string apiBaseUri)
{
try
{
using (var client = new HttpClient())
{
//setup client
client.BaseAddress = new Uri(apiBaseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.ASCII.GetBytes($"{userName}:{password}")));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//send request
var responseMessage = await client.GetStringAsync(apiBaseUri);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
}
}
if you have any comments on my code i would love to hear it.
thanks.
lidor
This might Help
you need to get RestSharp for this to work
var client = new RestClient("https://api.intrinio.com/companies?ticker=AAPL");
var request = new RestRequest(Method.GET);
request.AddHeader("cache-control", "no-cache");
request.AddHeader("authorization", "Basic MGU0NWIxZmIwZDFlMGNkMDEzY2Y2Y2I5MmRlNjk2N2M6MjNjYjM3OTQ3ZmFmMjQ0OWI1MWRjMWQ1NGU2ZGE1Zjc=");
IRestResponse response = client.Execute(request);
and you can try to convert it to an object by
try
{
dynamic x = Newtonsoft.Json.JsonConvert.DeserializeObject<RootObject>(response.Content, new Newtonsoft.Json.JsonSerializerSettings() { NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore });
return x;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return null;
}
and i do recommend of using http://json2csharp.com/
to create your C# Object
More Information
To get the Value that is used for authorization you can use this method
public static string Base64Encode(string key)
{
var value = System.Text.Encoding.UTF8.GetBytes(key);
return System.Convert.ToBase64String(value);
}
to get the exact value make sure the username and password are concatenated, (username first , password second) and then passed to the method

consuming a RESTFUL web service in c# with JSON [duplicate]

This is the code I have so far:
public class Class1
{
private const string URL = "https://sub.domain.com/objects.json?api_key=123";
private const string DATA = #"{""object"":{""name"":""Name""}}";
static void Main(string[] args)
{
Class1.CreateObject();
}
private static void CreateObject()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = DATA.Length;
StreamWriter requestWriter = new StreamWriter(request.GetRequestStream(), System.Text.Encoding.ASCII);
requestWriter.Write(DATA);
requestWriter.Close();
try {
WebResponse webResponse = request.GetResponse();
Stream webStream = webResponse.GetResponseStream();
StreamReader responseReader = new StreamReader(webStream);
string response = responseReader.ReadToEnd();
Console.Out.WriteLine(response);
responseReader.Close();
} catch (Exception e) {
Console.Out.WriteLine("-----------------");
Console.Out.WriteLine(e.Message);
}
}
}
The problem is that I think the exception block is being triggered (because when I remove the try-catch, I get a server error (500) message. But I don't see the Console.Out lines I put in the catch block.
My Console:
The thread 'vshost.NotifyLoad' (0x1a20) has exited with code 0 (0x0).
The thread '<No Name>' (0x1988) has exited with code 0 (0x0).
The thread 'vshost.LoadReference' (0x1710) has exited with code 0 (0x0).
'ConsoleApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'c:\users\l. preston sego iii\documents\visual studio 11\Projects\ConsoleApplication1\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe', Symbols loaded.
'ConsoleApplication1.vshost.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\Microsoft.Net\assembly\GAC_MSIL\System.Configuration\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll', Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
A first chance exception of type 'System.Net.WebException' occurred in System.dll
The thread 'vshost.RunParkingWindow' (0x184c) has exited with code 0 (0x0).
The thread '<No Name>' (0x1810) has exited with code 0 (0x0).
The program '[2780] ConsoleApplication1.vshost.exe: Program Trace' has exited with code 0 (0x0).
The program '[2780] ConsoleApplication1.vshost.exe: Managed (v4.0.30319)' has exited with code 0 (0x0).
The ASP.NET Web API has replaced the WCF Web API previously mentioned.
I thought I'd post an updated answer since most of these responses are from early 2012, and this thread is one of the top results when doing a Google search for "call restful service C#".
Current guidance from Microsoft is to use the Microsoft ASP.NET Web API Client Libraries to consume a RESTful service. This is available as a NuGet package, Microsoft.AspNet.WebApi.Client. You will need to add this NuGet package to your solution.
Here's how your example would look when implemented using the ASP.NET Web API Client Library:
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
namespace ConsoleProgram
{
public class DataObject
{
public string Name { get; set; }
}
public class Class1
{
private const string URL = "https://sub.domain.com/objects.json";
private string urlParameters = "?api_key=123";
static void Main(string[] args)
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(URL);
// Add an Accept header for JSON format.
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
// List data response.
HttpResponseMessage response = client.GetAsync(urlParameters).Result; // Blocking call! Program will wait here until a response is received or a timeout occurs.
if (response.IsSuccessStatusCode)
{
// Parse the response body.
var dataObjects = response.Content.ReadAsAsync<IEnumerable<DataObject>>().Result; //Make sure to add a reference to System.Net.Http.Formatting.dll
foreach (var d in dataObjects)
{
Console.WriteLine("{0}", d.Name);
}
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
// Make any other calls using HttpClient here.
// 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();
}
}
}
If you plan on making multiple requests, you should re-use your HttpClient instance. See this question and its answers for more details on why a using statement was not used on the HttpClient instance in this case: Do HttpClient and HttpClientHandler have to be disposed between requests?
For more details, including other examples, see Call a Web API From a .NET Client (C#)
This blog post may also be useful: Using HttpClient to Consume ASP.NET Web API REST Services
My suggestion would be to use RestSharp. You can make calls to REST services and have them cast into POCO objects with very little boilerplate code to actually have to parse through the response. This will not solve your particular error, but it answers your overall question of how to make calls to REST services. Having to change your code to use it should pay off in the ease of use and robustness moving forward. That is just my two cents though.
Example:
namespace RestSharpThingy
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using RestSharp;
public static class Program
{
public static void Main()
{
Uri baseUrl = new Uri("https://httpbin.org/");
IRestClient client = new RestClient(baseUrl);
IRestRequest request = new RestRequest("get", Method.GET) { Credentials = new NetworkCredential("testUser", "P455w0rd") };
request.AddHeader("Authorization", "Bearer qaPmk9Vw8o7r7UOiX-3b-8Z_6r3w0Iu2pecwJ3x7CngjPp2fN3c61Q_5VU3y0rc-vPpkTKuaOI2eRs3bMyA5ucKKzY1thMFoM0wjnReEYeMGyq3JfZ-OIko1if3NmIj79ZSpNotLL2734ts2jGBjw8-uUgKet7jQAaq-qf5aIDwzUo0bnGosEj_UkFxiJKXPPlF2L4iNJSlBqRYrhw08RK1SzB4tf18Airb80WVy1Kewx2NGq5zCC-SCzvJW-mlOtjIDBAQ5intqaRkwRaSyjJ_MagxJF_CLc4BNUYC3hC2ejQDoTE6HYMWMcg0mbyWghMFpOw3gqyfAGjr6LPJcIly__aJ5__iyt-BTkOnMpDAZLTjzx4qDHMPWeND-TlzKWXjVb5yMv5Q6Jg6UmETWbuxyTdvGTJFzanUg1HWzPr7gSs6GLEv9VDTMiC8a5sNcGyLcHBIJo8mErrZrIssHvbT8ZUPWtyJaujKvdgazqsrad9CO3iRsZWQJ3lpvdQwucCsyjoRVoj_mXYhz3JK3wfOjLff16Gy1NLbj4gmOhBBRb8rJnUXnP7rBHs00FAk59BIpKLIPIyMgYBApDCut8V55AgXtGs4MgFFiJKbuaKxq8cdMYEVBTzDJ-S1IR5d6eiTGusD5aFlUkAs9NV_nFw");
request.AddParameter("clientId", 123);
IRestResponse<RootObject> response = client.Execute<RootObject>(request);
if (response.IsSuccessful)
{
response.Data.Write();
}
else
{
Console.WriteLine(response.ErrorMessage);
}
Console.WriteLine();
string path = Assembly.GetExecutingAssembly().Location;
string name = Path.GetFileName(path);
request = new RestRequest("post", Method.POST);
request.AddFile(name, File.ReadAllBytes(path), name, "application/octet-stream");
response = client.Execute<RootObject>(request);
if (response.IsSuccessful)
{
response.Data.Write();
}
else
{
Console.WriteLine(response.ErrorMessage);
}
Console.ReadLine();
}
private static void Write(this RootObject rootObject)
{
Console.WriteLine("clientId: " + rootObject.args.clientId);
Console.WriteLine("Accept: " + rootObject.headers.Accept);
Console.WriteLine("AcceptEncoding: " + rootObject.headers.AcceptEncoding);
Console.WriteLine("AcceptLanguage: " + rootObject.headers.AcceptLanguage);
Console.WriteLine("Authorization: " + rootObject.headers.Authorization);
Console.WriteLine("Connection: " + rootObject.headers.Connection);
Console.WriteLine("Dnt: " + rootObject.headers.Dnt);
Console.WriteLine("Host: " + rootObject.headers.Host);
Console.WriteLine("Origin: " + rootObject.headers.Origin);
Console.WriteLine("Referer: " + rootObject.headers.Referer);
Console.WriteLine("UserAgent: " + rootObject.headers.UserAgent);
Console.WriteLine("origin: " + rootObject.origin);
Console.WriteLine("url: " + rootObject.url);
Console.WriteLine("data: " + rootObject.data);
Console.WriteLine("files: ");
foreach (KeyValuePair<string, string> kvp in rootObject.files ?? Enumerable.Empty<KeyValuePair<string, string>>())
{
Console.WriteLine("\t" + kvp.Key + ": " + kvp.Value);
}
}
}
public class Args
{
public string ClientId { get; set; }
}
public class Headers
{
public string Accept { get; set; }
public string AcceptEncoding { get; set; }
public string AcceptLanguage { get; set; }
public string Authorization { get; set; }
public string Connection { get; set; }
public string Dnt { get; set; }
public string Host { get; set; }
public string Origin { get; set; }
public string Referer { get; set; }
public string UserAgent { get; set; }
}
public class RootObject
{
public Args args { get; set; }
public Headers Headers { get; set; }
public string Origin { get; set; }
public string Url { get; set; }
public string Data { get; set; }
public Dictionary<string, string> Files { get; set; }
}
}
Unrelated, I'm sure, but do wrap your IDisposable objects in using blocks to ensure proper disposal:
using System;
using System.Net;
using System.IO;
namespace ConsoleProgram
{
public class Class1
{
private const string URL = "https://sub.domain.com/objects.json?api_key=123";
private const string DATA = #"{""object"":{""name"":""Name""}}";
static void Main(string[] args)
{
Class1.CreateObject();
}
private static void CreateObject()
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/json";
request.ContentLength = DATA.Length;
using (Stream webStream = request.GetRequestStream())
using (StreamWriter requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
{
requestWriter.Write(DATA);
}
try
{
WebResponse webResponse = request.GetResponse();
using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
using (StreamReader responseReader = new StreamReader(webStream))
{
string response = responseReader.ReadToEnd();
Console.Out.WriteLine(response);
}
}
catch (Exception e)
{
Console.Out.WriteLine("-----------------");
Console.Out.WriteLine(e.Message);
}
}
}
}
Here are a few different ways of calling an external API in C# (updated 2019).
.NET's built-in ways:
WebRequest& WebClient - verbose APIs & Microsoft's documentation is not very easy to follow
HttpClient - .NET's newest kid on the block & much simpler to use than above.
Free, open-source NuGet Packages, which frankly have a much better developer experience than .NET's built in clients:
ServiceStack.Text (1,000 GitHub stars, 7 million NuGet downloads) (*) - fast, light and resilient.
RestSharp (6,000 GitHub stars, 23 million NuGet downloads) (*) - simple REST and HTTP API Client
Flurl (1,700 GitHub stars, 3 million NuGet downloads) (*)- a fluent, portable, testable HTTP client library
All the above packages provide a great developer experience (i.e., concise, easy API) and are well maintained.
(*) as at August 2019
Example: Getting a Todo item from a Fake Rest API using ServiceStack.Text.
The other libraries have very similar syntax.
class Program
{
static void Main(string[] args)
{
// Fake rest API
string url = "https://jsonplaceholder.typicode.com/todos/1";
// GET data from API & map to POCO
var todo = url.GetJsonFromUrl().FromJson<Todo>();
// Print the result to screen
todo.PrintDump();
}
public class Todo
{
public int UserId { get; set; }
public int Id { get; set; }
public string Title { get; set; }
public bool Completed { get; set; }
}
}
Running the above example in a .NET Core Console app, produces the following output.
Install these packages using NuGet
Install-Package ServiceStack.Text, or
Install-Package RestSharp, or
Install-Package Flurl.Http
A solution in ASP.NET Core:
using Newtonsoft.Json;
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Configuration;
namespace WebApp
{
public static class HttpHelper
{
// In my case this is https://localhost:44366/
private static readonly string apiBasicUri = ConfigurationManager.AppSettings["apiBasicUri"];
public static async Task Post<T>(string url, T contentValue)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(apiBasicUri);
var content = new StringContent(JsonConvert.SerializeObject(contentValue), Encoding.UTF8, "application/json");
var result = await client.PostAsync(url, content);
result.EnsureSuccessStatusCode();
}
}
public static async Task Put<T>(string url, T stringValue)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(apiBasicUri);
var content = new StringContent(JsonConvert.SerializeObject(stringValue), Encoding.UTF8, "application/json");
var result = await client.PutAsync(url, content);
result.EnsureSuccessStatusCode();
}
}
public static async Task<T> Get<T>(string url)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(apiBasicUri);
var result = await client.GetAsync(url);
result.EnsureSuccessStatusCode();
string resultContentString = await result.Content.ReadAsStringAsync();
T resultContent = JsonConvert.DeserializeObject<T>(resultContentString);
return resultContent;
}
}
public static async Task Delete(string url)
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(apiBasicUri);
var result = await client.DeleteAsync(url);
result.EnsureSuccessStatusCode();
}
}
}
}
To post, use something like this:
await HttpHelper.Post<Setting>($"/api/values/{id}", setting);
Example for delete:
await HttpHelper.Delete($"/api/values/{id}");
Example to get a list:
List<ClaimTerm> claimTerms = await HttpHelper.Get<List<ClaimTerm>>("/api/values/");
Example to get only one:
ClaimTerm processedClaimImage = await HttpHelper.Get<ClaimTerm>($"/api/values/{id}");
Please use the below code for your REST API request:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Json;
namespace ConsoleApplication2
{
class Program
{
private const string URL = "https://XXXX/rest/api/2/component";
private const string DATA = #"{
""name"": ""Component 2"",
""description"": ""This is a JIRA component"",
""leadUserName"": ""xx"",
""assigneeType"": ""PROJECT_LEAD"",
""isAssigneeTypeValid"": false,
""project"": ""TP""}";
static void Main(string[] args)
{
AddComponent();
}
private static void AddComponent()
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
client.BaseAddress = new System.Uri(URL);
byte[] cred = UTF8Encoding.UTF8.GetBytes("username:password");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(cred));
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
System.Net.Http.HttpContent content = new StringContent(DATA, UTF8Encoding.UTF8, "application/json");
HttpResponseMessage messge = client.PostAsync(URL, content).Result;
string description = string.Empty;
if (messge.IsSuccessStatusCode)
{
string result = messge.Content.ReadAsStringAsync().Result;
description = result;
}
}
}
}
Calling a REST API when using .NET 4.5 or .NET Core
I would suggest DalSoft.RestClient (caveat: I created it). The reason being, because it uses dynamic typing, you can wrap everything up in one fluent call including serialization/de-serialization. Below is a working PUT example:
dynamic client = new RestClient("http://jsonplaceholder.typicode.com");
var post = new Post { title = "foo", body = "bar", userId = 10 };
var result = await client.Posts(1).Put(post);
GET:
// GET JSON Response
public WeatherResponseModel GET(string url) {
WeatherResponseModel model = new WeatherResponseModel();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
try {
WebResponse response = request.GetResponse();
using(Stream responseStream = response.GetResponseStream()) {
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
model = JsonConvert.DeserializeObject < WeatherResponseModel > (reader.ReadToEnd());
}
} catch (WebException ex) {
WebResponse errorResponse = ex.Response;
using(Stream responseStream = errorResponse.GetResponseStream()) {
StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
String errorText = reader.ReadToEnd();
// Log errorText
}
throw;
}
return model;
}
POST:
// POST a JSON string
void POST(string url, string jsonContent) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
Byte[]byteArray = encoding.GetBytes(jsonContent);
request.ContentLength = byteArray.Length;
request.ContentType = # "application/json";
using(Stream dataStream = request.GetRequestStream()) {
dataStream.Write(byteArray, 0, byteArray.Length);
}
long length = 0;
try {
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
// Got response
length = response.ContentLength;
}
} catch (WebException ex) {
WebResponse errorResponse = ex.Response;
using(Stream responseStream = errorResponse.GetResponseStream()) {
StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
String errorText = reader.ReadToEnd();
// Log errorText
}
throw;
}
}
Note: To serialize and desirialze JSON, I used the Newtonsoft.Json NuGet package.
Check out Refit for making calls to REST services from .NET. I've found it very easy to use:
Refit: The automatic type-safe REST library for .NET Core, Xamarin and
.NET
Refit is a library heavily inspired by Square's Retrofit library, and
it turns your REST API into a live interface:
public interface IGitHubApi {
[Get("/users/{user}")]
Task<User> GetUser(string user);
}
// The RestService class generates an implementation of IGitHubApi
// that uses HttpClient to make its calls:
var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");
var octocat = await gitHubApi.GetUser("octocat");
This is example code that works for sure. It took me a day to make this to read a set of objects from a REST service:
RootObject is the type of the object I'm reading from the REST service.
string url = #"http://restcountries.eu/rest/v1";
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(IEnumerable<RootObject>));
WebClient syncClient = new WebClient();
string content = syncClient.DownloadString(url);
using (MemoryStream memo = new MemoryStream(Encoding.Unicode.GetBytes(content)))
{
IEnumerable<RootObject> countries = (IEnumerable<RootObject>)serializer.ReadObject(memo);
}
Console.Read();
I did it in this simple way, with Web API 2.0. You can remove UseDefaultCredentials. I used it for my own use cases.
List<YourObject> listObjects = new List<YourObject>();
string response = "";
using (var client = new WebClient() { UseDefaultCredentials = true })
{
response = client.DownloadString(apiUrl);
}
listObjects = JsonConvert.DeserializeObject<List<YourObject>>(response);
return listObjects;
var TakingRequset = WebRequest.Create("http://xxx.acv.com/MethodName/Get");
TakingRequset.Method = "POST";
TakingRequset.ContentType = "text/xml;charset=utf-8";
TakingRequset.PreAuthenticate = true;
//---Serving Request path query
var PAQ = TakingRequset.RequestUri.PathAndQuery;
//---creating your xml as per the host reqirement
string xmlroot=#"<root><childnodes>passing parameters</childnodes></root>";
string xmlroot2=#"<root><childnodes>passing parameters</childnodes></root>";
//---Adding Headers as requested by host
xmlroot2 = (xmlroot2 + "XXX---");
//---Adding Headers Value as requested by host
// var RequestheaderVales = Method(xmlroot2);
WebProxy proxy = new WebProxy("XXXXX-----llll", 8080);
proxy.Credentials = new NetworkCredential("XXX---uuuu", "XXX----", "XXXX----");
System.Net.WebRequest.DefaultWebProxy = proxy;
// Adding The Request into Headers
TakingRequset.Headers.Add("xxx", "Any Request Variable ");
TakingRequset.Headers.Add("xxx", "Any Request Variable");
byte[] byteData = Encoding.UTF8.GetBytes(xmlroot);
TakingRequset.ContentLength = byteData.Length;
using (Stream postStream = TakingRequset.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
postStream.Close();
}
StreamReader stredr = new StreamReader(TakingRequset.GetResponse().GetResponseStream());
string response = stredr.ReadToEnd();
The answer marked here suggests using HttpClient directly and the disposing of it. This might work, but it's quite easy to run in to problems with HttpClient if you don't use it correctly.
If you're going to use HttpClient, you're better off handing over the creation/disposal of HttpClients to a third-party library that uses the factory pattern. RestClient.Net is one such library.
It comes with a very basic HttpClient factory so that you don't run in to the socket exhaustion problem,
public class DefaultHttpClientFactory : IHttpClientFactory, IDisposable
{
#region Fields
private bool disposed;
private readonly ConcurrentDictionary<string, Lazy<HttpClient>> _httpClients;
private readonly Func<string, Lazy<HttpClient>> _createClientFunc;
#endregion
#region Constructor
public DefaultHttpClientFactory() : this(null)
{
}
public DefaultHttpClientFactory(Func<string, Lazy<HttpClient>> createClientFunc)
{
_createClientFunc = createClientFunc;
_httpClients = new ConcurrentDictionary<string, Lazy<HttpClient>>();
if (_createClientFunc != null) return;
_createClientFunc = name =>
{
return new Lazy<HttpClient>(() => new HttpClient(), LazyThreadSafetyMode.ExecutionAndPublication);
};
}
#endregion
#region Implementation
public HttpClient CreateClient(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
return _httpClients.GetOrAdd(name, _createClientFunc).Value;
}
public void Dispose()
{
if (disposed) return;
disposed = true;
foreach (var name in _httpClients.Keys)
{
_httpClients[name].Value.Dispose();
}
}
#endregion
}
But Microsoft's IHttpClientFactory implementation can also be used for the latest and greatest:
var serviceCollection = new ServiceCollection();
var baseUri = new Uri("http://www.test.com");
serviceCollection.AddSingleton(typeof(ISerializationAdapter), typeof(NewtonsoftSerializationAdapter));
serviceCollection.AddSingleton(typeof(ILogger), typeof(ConsoleLogger));
serviceCollection.AddSingleton(typeof(IClient), typeof(Client));
serviceCollection.AddDependencyInjectionMapping();
serviceCollection.AddTransient<TestHandler>();
//Make sure the HttpClient is named the same as the Rest Client
serviceCollection.AddSingleton<IClient>(x => new Client(name: clientName, httpClientFactory: x.GetRequiredService<IHttpClientFactory>()));
serviceCollection.AddHttpClient(clientName, (c) => { c.BaseAddress = baseUri; })
.AddHttpMessageHandler<TestHandler>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var client = serviceProvider.GetService<IClient>();
await client.GetAsync<object>();
RestClient.Net takes in to account dependency injection, mocking, IoC containers, unit testability, and above all is fast. I've hunted around and the only the other client that seems to work in a similar capacity is Flurl.Http.
We have started using speakeasy. It is great:
https://github.com/jonnii/SpeakEasy
// create a client
var client = HttpClient.Create("http://example.com/api");
// get some companies!
var companies = client.Get("companies").OnOk().As<List<Company>>();
// upload a company, with validation error support
client.Post(company, "companies")
.On(HttpStatusCode.BadRequest, (List<ValidationError> errors) => {
Console.WriteLine("Ruh Roh, you have {0} validation errors", errors.Count());
})
.On(HttpStatusCode.Created, () => Console.WriteLine("Holy moly you win!"));
// update a company
client.Put(company, "company/:id", new { id = "awesome-sauce" })
.OnOk(() => Console.WriteLine("Company updated"));
// run a search
client.Get("images/:category", new { category = "cats", breed = "omg the cutest", size = "kittens" })
.OnOk().As<List<Image>>();
// make an asynchronous request
var response = await client.GetAsync("companies/:id", new { id = 5 })
response.OnOk(UpdateCompaniesCallback)
Since you are using Visual Studio 11 Beta, you will want to use the latest and greatest. The new Web API contains classes for this.
See HttpClient: http://wcf.codeplex.com/wikipage?title=WCF%20HTTP
HTTP GET Request
string api = this.configuration["getApiUrl"];//Read from Iconfiguration object injected
public async Task<HttpResponseMessage> GetAsync(string api, ILogger log, params dynamic[] parameters)
{
log.LogInformation($"Get Token");
var token = await GetTokenAsync(this.configuration["ClientId"], this.configuration["AppKey"]).ConfigureAwait(false);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(BearerTokenName, token);
var apiBaseUrl = this.configuration["BaseUrl"];
client.BaseAddress = new Uri(apiBaseUrl);
var apiUrl = ConstructUrl(api, parameters);
var result = await client.GetAsync(apiUrl).ConfigureAwait(false);
if (result.StatusCode == System.Net.HttpStatusCode.OK)
{
return result;
}
else
{
throw new HttpResponseException(new HttpResponseMessage(result.StatusCode) { Content = new StringContent(result.ReasonPhrase) });
}
}
}
Read String from HttpResponseMessage as below
var client = await this.httpClientService.GetAsync(url, logger, Convert.ToInt32(Id, CultureInfo.InvariantCulture)).ConfigureAwait(false);
var response = await client.Content.ReadAsStringAsync();
HTTP POST Request
public async Task<string> PostAsync(string api, string contentValue, ILogger logger)
{
var token = await GetTokenAsync(this.configuration["ClientId"], this.configuration["AppKey"]).ConfigureAwait(false);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(BearerTokenName, token);
client.BaseAddress = new Uri(resource);
var content = new StringContent(contentValue, Encoding.UTF8, MediaTypeNames.Application.Json);
var result = await client.PostAsync(new Uri(api, UriKind.Relative), content).ConfigureAwait(false);
if (result.StatusCode == System.Net.HttpStatusCode.OK)
{
return await result.Content.ReadAsStringAsync();
}
else
{
throw new HttpResponseException(new HttpResponseMessage(result.StatusCode) { Content = new StringContent(result.ReasonPhrase) });
}
}
}
var response = await this.httpClientService.PostAsync(this.configuration["getDetails"], content, this.configuration["ApiBaseUrl"], logger).ConfigureAwait(false);
catch (System.Web.Http.HttpResponseException httpException)
{
if (httpException.Response.StatusCode == HttpStatusCode.Unauthorized)
{
logger.LogError($"Failed To Update", httpException);
}
else
{
throw;
}
}
return response;
The first step is to create the helper class for the HTTP client.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
namespace callApi.Helpers
{
public class CallApi
{
private readonly Uri BaseUrlUri;
private HttpClient client = new HttpClient();
public CallApi(string baseUrl)
{
BaseUrlUri = new Uri(baseUrl);
client.BaseAddress = BaseUrlUri;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
public HttpClient getClient()
{
return client;
}
public HttpClient getClientWithBearer(string token)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
return client;
}
}
}
Then you can use this class in your code.
This is an example of how you call the REST API without bearer using the above class.
// GET API/values
[HttpGet]
public async Task<ActionResult<string>> postNoBearerAsync(string email, string password,string baseUrl, string action)
{
var request = new LoginRequest
{
email = email,
password = password
};
var callApi = new CallApi(baseUrl);
var client = callApi.getClient();
HttpResponseMessage response = await client.PostAsJsonAsync(action, request);
if (response.IsSuccessStatusCode)
return Ok(await response.Content.ReadAsAsync<string>());
else
return NotFound();
}
This is an example of how you can call the REST API that require bearer.
// GET API/values
[HttpGet]
public async Task<ActionResult<string>> getUseBearerAsync(string token, string baseUrl, string action)
{
var callApi = new CallApi(baseUrl);
var client = callApi.getClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await client.GetAsync(action);
if (response.IsSuccessStatusCode)
{
return Ok(await response.Content.ReadAsStringAsync());
}
else
return NotFound();
}
You can also refer to the below repository if you want to see the working example of how it works.
https://github.com/mokh223/callApi

Categories

Resources