Call and consume Web API in winform using C#.net
You can take a look at the following docs tutorial:
- Call a Web API From a .NET Client
But as an answer, here I will share a quick and short a step by step guide about how to call and consume web API in Windows forms:
Install Package - Install the
Microsoft.AspNet.WebApi.Client
NuGet package (Web API Client Libraries).Open Tools menu → NuGet Package Manager → Package Manager Console → In the Package Manager Console window, type the following command:
Install-Package Microsoft.AspNet.WebApi.Client
You can install package by right click on project and choosing Manage NuGet Packages as well.
Set up HttpClient - Create an instance of
HttpClient
and set up itsBaseAddress
andDefaultRequestHeaders
. For example:// In the class
static HttpClient client = new HttpClient();
// Put the following code where you want to initialize the class
// It can be the static constructor or a one-time initializer
client.BaseAddress = new Uri("http://localhost:4354/api/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));Send Request - To send the requests, you can use the following methods of the
HttpClient
:- GET:
GetAsync
,GetStringAsync
,GetByteArrayAsync
,GetStreamAsync
- POST:
PostAsync
,PostAsJsonAsync
,PostAsXmlAsync
- PUT:
PutAsync
,PutAsJsonAsync
,PutAsXmlAsync
- DELETE:
DeleteAsync
- Another HTTP method:
Send
Note: To set the URL of the request for the methods, keep in mind, since you have specified the base URL when you defined the
client
, then here for these methods, just pass path, route values and query strings, for example:// Assuming http://localhost:4354/api/ as BaseAddress
var response = await client.GetAsync("products");or
// Assuming http://localhost:4354/api/ as BaseAddress
var product = new Product() { Name = "P1", Price = 100, Category = "C1" };
var response = await client.PostAsJsonAsync("products", product);- GET:
Get the Response
To get the response, if you have used methods like
GetStringAsync
, then you have the response as string and it's enough to parse the response. If the response is a Json content which you know, you can easily useJsonConvert
class ofNewtonsoft.Json
package to parse it. For example:// Assuming http://localhost:4354/api/ as BaseAddress
var response = await client.GetStringAsync("product");
var data = JsonConvert.DeserializeObject<List<Product>>(response);
this.productBindingSource.DataSource = data;If you have used methods like
GetAsync
orPostAsJsonAsync
and you have anHttpResponseMessage
then you can useReadAsAsync
,ReadAsByteArrayAsync
,ReadAsStreamAsync
, `ReadAsStringAsync, for example:// Assuming http://localhost:4354/api/ as BaseAddress
var response = await client.GetAsync("products");
var data = await response.Content.ReadAsAsync<IEnumerable<Product>>();
this.productBindingSource.DataSource = data;
Performance Tip
HttpClient
is a type that is meant to be created once and then shared. So don't try to put it in a using block every time that you want to use it. Instead, create an instance of the class and share it through a static member. To read more about this, take a look at Improper Instantiation antipattern
Design Tip
- Try to avoid mixing the Web API related code with your application logic. For example let's say you have a product Web API service. Then to use it, first define an
IProductServieClient
interface, then as an implementation put all the WEB API logic inside theProductWebAPIClientService
which you implement to contain codes to interact with WEB API. Your application should rely onIProductServieClient
. (SOLID Principles, Dependency Inversion).
Call and get response from web api in a winform c# application
First creating model from Json:
use a online model generator like Json2C#, for the Json that you have posted, following is the model generated:
public class EffectiveParams
{
public string data_set { get; set; }
public List<string> base_currencies { get; set; }
public List<string> quote_currencies { get; set; }
}
public class Meta
{
public EffectiveParams effective_params { get; set; }
public string endpoint { get; set; }
public DateTime request_time { get; set; }
public List<object> skipped_currency_pairs { get; set; }
}
public class Quote
{
public string base_currency { get; set; }
public string quote_currency { get; set; }
public string bid { get; set; }
public string ask { get; set; }
public string midpoint { get; set; }
}
public class RootObject
{
public Meta meta { get; set; }
public List<Quote> quotes { get; set; }
}Now connecting to the
WebAPI
usingHttpClient
, which has the option to return bothJson
andCSV
, I would preferJSON
being standard, which can also be consumed easily by variety of clients, use the following simple generic methods:
Assuming it is GET only call, just supply the Host and API details to the generic Process method underneath:
public async Task<TResponse> Process<TResponse>(string host,string api)
{
// Execute Api call Async
var httpResponseMessage = await MakeApiCall(host,api);
// Process Json string result to fetch final deserialized model
return await FetchResult<TResponse>(httpResponseMessage);
}
public async Task<HttpResponseMessage> MakeApiCall(string host,string api)
{
// Create HttpClient
var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }) { BaseAddress = new Uri(host) };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Make an API call and receive HttpResponseMessage
HttpResponseMessage responseMessage = await client.GetAsync(api, HttpCompletionOption.ResponseContentRead);
return responseMessage;
}
public async Task<T> FetchResult<T>(HttpResponseMessage result)
{
if (result.IsSuccessStatusCode)
{
// Convert the HttpResponseMessage to string
var resultArray = await result.Content.ReadAsStringAsync();
// Json.Net Deserialization
var final = JsonConvert.DeserializeObject<T>(resultArray);
return final;
}
return default(T);
}
How to use:
Simply call:
var rootObj = await Process<RootObject>("https://www1.oanda.com/rates/", "api/v2/rates/");
You receive the deserialized
RootObject
as shown in the model aboveFor anything further complex processing like sending input to the call with http body, above generic code needs further modification, it is currently only specific to your requirement
Edit 1: (Making the entry call Synchronous)
To make the overall call synchronous, use the
GetAwaiter().GetResult()
at the topmost level, Main method will be converted to, rest all will remain same as in the sample (async methods)void Main()
{
var rootObj = Process<RootObject>("https://www1.oanda.com/rates/", "api/v2/rates/").GetAwaiter().GetResult();
}
Edit 2: (Making complete code Synchronous)
void Main()
{
var rootObj = Process<RootObject>("https://www1.oanda.com/rates/", "api/v2/rates/");
}
public TResponse Process<TResponse>(string host, string api)
{
// Execute Api call
var httpResponseMessage = MakeApiCall(host, api);
// Process Json string result to fetch final deserialized model
return FetchResult<TResponse>(httpResponseMessage);
}
public HttpResponseMessage MakeApiCall(string host, string api)
{
// Create HttpClient
var client = new HttpClient(new HttpClientHandler { UseDefaultCredentials = true }) { BaseAddress = new Uri(host) };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// Make an API call and receive HttpResponseMessage
HttpResponseMessage responseMessage = client.GetAsync(api, HttpCompletionOption.ResponseContentRead).GetAwaiter().GetResult();
return responseMessage;
}
public T FetchResult<T>(HttpResponseMessage result)
{
if (result.IsSuccessStatusCode)
{
// Convert the HttpResponseMessage to string
var resultArray = result.Content.ReadAsStringAsync().GetAwaiter().GetResult();
// Json.Net Deserialization
var final = JsonConvert.DeserializeObject<T>(resultArray);
return final;
}
return default(T);
}
How to get data by api use Windows Form
On the browser, I could get data like this.(JSON format)
This is means you are making an HttpGet
call with no parameters as I can see from the Url and in any case there's no HttpBody. For any other call like HttpPost, you have to use a tool like Postman, Fiddler
Following is the simple code to make a Http Get call using C#:
// Create HttpClient
var client = new HttpClient { BaseAddress = new Uri("http://localhost:8888/") };
// Assign default header (Json Serialization)
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(ApiConstant.JsonHeader));
// Make an API call and receive HttpResponseMessage
var responseMessage = await client.GetAsync("PersonList", HttpCompletionOption.ResponseContentRead);
// Convert the HttpResponseMessage to string
var resultArray = await result.Content.ReadAsStringAsync();
// Deserialize the Json string into type using JsonConvert
var personList = JsonConvert.DeserializeObject<List<Person>>(resultArray);
How it works
HttpClient
is object which encompass the api service address- We ensure that assigned header is Json type for serialization / communication
- Make an Async Http Get Call
HttpResponseMessage
is used to extract string, which is de-serialized intoList<Person>
using NewtonSoft Json
Please note Async
call means encompassing method shall be Async
Expected Schema for the
Person
class to fill theList<Person>
using de-serialization:
public class Person
{
public int id {get;set;}
public string Name {get;set;}
public int age {get;set;}
}
Where to call the code - Winform / Add new class
Standard mechanism would be to create a generic helper library / class, from which all the API calls are done, results are fetched, winform shall just do the data binding, not have the processing code
Hosting ASP.NET Core API in a Windows Forms Application
Hosting ASP.NET CORE API in a Windows Forms Application and Interaction with Form
Here is a basic step by step example about how to create a project to host ASP.NET CORE API inside a Windows Forms Application and perform some interaction with Form.
To do so, follow these steps:
Create a Windows Forms Application name it
MyWinFormsApp
Open
Form1
in design mode and drop aTextBox
on it.Change the
Modifiers
property of thetextBox1
in designer toPublic
and save it.Install
Microsoft.AspNetCore.Mvc
packageInstall
Microsoft.AspNetCore
packageCreate a
Startup.cs
file in the root of the project, and copy the following code:using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace MyWinFormsApp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
}
}
}Copy the following code in
Program.cs
:using System;
using System.Threading;
using System.Windows.Forms;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
namespace MyWinFormsApp
{
public class Program
{
public static Form1 MainForm { get; private set; }
[STAThread]
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().RunAsync();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainForm = new Form1();
Application.Run(MainForm);
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}Create a folder called
Controllers
in the root of the project.Create
ValuesController.cs
in theControllers
folder and copy the following code to file:using System;
using Microsoft.AspNetCore.Mvc;
namespace MyWinFormsApp.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
[HttpGet]
public ActionResult<string> Get()
{
string text = "";
Program.MainForm.Invoke(new Action(() =>
{
text = Program.MainForm.textBox1.Text;
}));
return text;
}
[HttpGet("{id}")]
public ActionResult Get(string id)
{
Program.MainForm.Invoke(new Action(() =>
{
Program.MainForm.textBox1.Text = id;
}));
return Ok();
}
}
}Run the application.
Type "hi" in the
textBox1
Open browser and browse http://localhost:5000/api/values → You will see
hi
as response.http://localhost:5000/api/values/bye → You will see
bye
intextBox1
Further Reading
You may also be interested in How to use Dependency Injection (DI) in Windows Forms (WinForms)
How do i get data from a web api into a c# windows forms app class
I have changed a bit your code and it seems to work well:
async void Main()
{
await InitClient();
// Pass the file title to the API
var result = await GetFilmAsync("it");
client.CancelPendingRequests();
client.Dispose();
}
// Changed name to be more meaningful
static async Task InitClient()
{
// Remove the part with your key and the film title from the general initialization
client.BaseAddress = new Uri("http://www.omdbapi.com/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
}
static async Task<Film> GetFilmAsync(string title)
{
Film film = null;
// Compose the path adding the key and the film title
string path = "?apikey=caa4fbc9&t=" + title;
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
string data = await response.Content.ReadAsStringAsync();
// This is the key point, the API returns a JSON string
// You need to convert it to your Film object.
// In this example I have used the very useful JSon.NET library
// that you can easily install with NuGet.
film = JsonConvert.DeserializeObject<Film>(data);
}
return film;
}
How to call a Web API GET method from a .NET client using also token authorization and parameters
[HttpGet]
[Route("api/[controller]/name={name}&email={email}phone={phone}&description={description}")]
public ActionResult<model_class> Get(string name, string email, string phone, string description) {
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("GET"), "https://Endpoint_or_API_URL "))
{
var base64authorization = Convert.ToBase64String(Encoding.ASCII.GetBytes("place_your_toke_here"));
request.Headers.TryAddWithoutValidation("Authorization", $"Basic {base64authorization}");
var response = await httpClient.SendAsync(request);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
result = await reader.ReadToEndAsync();
}
}
}
}
Related Topics
Server.Mappath - Physical Path Given, Virtual Path Expected
Where Are Clr-Defined Methods Like [Delegate].Begininvoke Documented
How to Log All Thrown Exceptions
How to Add My New User Control to the Toolbox or a New Winform
Datagrid Column Width Doesn't Auto-Update
No Access to the Session Information Through Signalr Hub. Is My Design Is Wrong
Why am I Getting 'One or More Types Required to Compile a Dynamic Expression Cannot Be Found.'
.Net: Unable to Cast Object to Interface It Implements
Extension Method on Enumeration, Not Instance of Enumeration
No Itemchecked Event in a Checkedlistbox
Why am I Getting Sehexception When Calling Roleenvironment.Getconfigurationsettingvalue("Mykey")
Programmatically Getting the Last Filled Excel Row Using C#
C# Structs: Unassigned Local Variable
How to Install a Windows Font Using C#
How to Get Current Regional Settings in C#
Ef Core 2.1 Hasconversion on All Properties of Type Datetime
Directoryinfo.Enumeratefiles(...) Causes Unauthorizedaccessexception (And Other Exceptions)