Get JSON from url, save to file, and finally CreateActivationService - c#

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

Related

c# API client using Desktop application

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

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();

Deadlock at consuming rest API [duplicate]

This question already has answers here:
await vs Task.Wait - Deadlock?
(3 answers)
Closed 5 years ago.
So I built a small program to consume a REST api, but it never finishes beacuse no data is received. I'm new to using Async and wait commands, so I have probably gotten it wrong somehow. The threads responsible for retrieving the data just times out after a couple of seconds. The url in itself is valid though and no exception seems to be thrown.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace Bot_Application1
{
[Serializable]
public class ConsumeFOAAS
{
private static HttpClient client = new HttpClient();
private static String message = "empty";
public String GetMessage()
{
RunAsync().Wait();
return message;
}
static async Task RunAsync()
{
client.BaseAddress = new Uri("http://foaas.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
try
{
message = await GetProductAsync("/because/:Insultinator");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static async Task<String> GetProductAsync(string path)
{
Debug.WriteLine("Inside GetProductAsync");
String product = "empty";
HttpResponseMessage response = await client.GetAsync(path); //<--This never finishes
Debug.WriteLine("Response: " + response);
if (response.IsSuccessStatusCode)
{
product = await response.Content.ReadAsStringAsync();
}
return product;
}
}
}
You shouldn't call .Wait(). The best wait to achieve what you want is :
public async Task<String> GetMessage()
{
return await RunAsync();
}
And change the RunAsync function :
static async Task<string> RunAsync() {
client.BaseAddress = new Uri("http://foaas.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/plain"));
try {
return await GetProductAsync("/because/:Insultinator");
} catch (Exception e) {
Console.WriteLine(e.Message);
}
}
Deadlock can be caused by task manager. Try using:
RunAsync().ConfigureAwait(false).Wait();
Explanation: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

How to change the body of text for C# .NET RequestBin HTTP API?

hey guys I'm new to C# and I wanted to try out Request Bin after seeing it in another youtube video, however it was a PHP video, can any of you please tell me how I can implement a body of text into the request so I can see it on the site? thank you :D here's my current code.
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace RequestBinExample
{
class Program
{
static void Main(string[] args)
{
var task = MakeRequest();
task.Wait();
var response = task.Result;
var body = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(body);
}
private static async Task<HttpResponseMessage> MakeRequest()
{
var httpClient = new HttpClient();
return await httpClient.GetAsync(new Uri("http://requestb.in/1hui2vv1"));
}
}
}
class Program
{
static void Main(string[] args)
{
var task = MakeRequest();
task.Wait();
var response = task.Result;
var body = response.Content.ReadAsStringAsync().Result;
Console.WriteLine(body);
Console.Read();
}
private static async Task<HttpResponseMessage> MakeRequest()
{
var httpClient = new HttpClient();
HttpContent requestContent = new StringContent("I am the message body");
return await httpClient.PostAsync("https://requestb.in/188bhf01", requestContent);
}
}
I think this should do the trick.

Using await on HttpClient in wpf project

I just following a sample in calling HttpClient in sync mode, it works fine in a Console application.
However, when I move it to a wpf application, the program hanged without any return.
I try to isolate the problem by building a separate class to handle a dummy request to visit www.google.com.
It seems that the application hang in calling client.GetAsync, may I know if there has any thing need to be changed from console application to wpf in this case?
Please find the source of both the console application and wpf as below,
Console application - works fine:
using System;
using System.Threading.Tasks;
using System.Net.Http;
namespace ca03
{
static class action
{
static async Task<string> DownloadPageAsync()
{
// ... Target page.
string page = "http://www.google.com/";
// ... Use HttpClient.
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(page))
using (HttpContent content = response.Content)
{
// ... Read the string.
string result = await content.ReadAsStringAsync();
// ... Display the result.
if (result != null &&
result.Length >= 50)
{
Console.WriteLine(result.Substring(0, 50) + "...");
}
return result;
}
}
public static string goDownload()
{
Task<string> x = DownloadPageAsync();
string result = x.Result;
return result;
}
}
class Program
{
static void Main(string[] args)
{
string data = action.goDownload();
Console.WriteLine(data);
Console.ReadLine();
}
}
}
WPF application: (just a plain project with a button added) - hang in GetAsync
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Net.Http;
namespace wpf02
{
static class action
{
static async Task<string> DownloadPageAsync()
{
// ... Target page.
string page = "http://www.google.com/";
// ... Use HttpClient.
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(page))
using (HttpContent content = response.Content)
{
// ... Read the string.
string result = await content.ReadAsStringAsync();
return result;
}
}
public static string goDownload()
{
Task<string> x = DownloadPageAsync();
string result = x.Result;
return result;
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button_Click(object sender, RoutedEventArgs e)
{
string data = action.goDownload();
Console.WriteLine(data);
}
}
}
This line is the problem:
string result = x.Result;
When you use the Result property, that blocks the current thread until the task has completed. That's a problem when your continuations are meant to run on the same thread...
Basically, there's no point in your goDownload method - just change your DownloadPageAsync method to be public, then change your button_Click method to also be async so you can await the result:
private async void button_Click(object sender, RoutedEventArgs e)
{
string data = await action.DownloadPageAsync();
Console.WriteLine(data);
}
Top-level reason of this - WPF ( as any UI app) have a UI-thread, that work with winwdows loop queue. Jon Skeet give you a simplest desigion, but you can use thread from CLR ThreadPool:
Task<string> t = Task.Run(() => DownloadPageAsync());
string result = = await t;

Categories

Resources