Call and Consume Web API in Winform Using C#.Net

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:

  1. 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.

  2. Set up HttpClient - Create an instance of HttpClient and set up its BaseAddress and DefaultRequestHeaders. 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"));
  3. 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);
  4. 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 use JsonConvert class of Newtonsoft.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 or PostAsJsonAsync and you have an HttpResponseMessage then you can use ReadAsAsync, 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 the ProductWebAPIClientService which you implement to contain codes to interact with WEB API. Your application should rely on IProductServieClient. (SOLID Principles, Dependency Inversion).

Call and get response from web api in a winform c# application

First creating model from Json:

  1. 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; }
    }
  2. Now connecting to the WebAPI using HttpClient, which has the option to return both Json and CSV, I would prefer JSON 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 above

  • For 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 into List<Person> using NewtonSoft Json

Please note Async call means encompassing method shall be Async

Expected Schema for the Person class to fill the List<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:

  1. Create a Windows Forms Application name it MyWinFormsApp

  2. Open Form1 in design mode and drop a TextBox on it.

  3. Change the Modifiers property of the textBox1 in designer to Public and save it.

  4. Install Microsoft.AspNetCore.Mvc package

  5. Install Microsoft.AspNetCore package

  6. Create 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();
    }
    }
    }
  7. 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>();
    }
    }
  8. Create a folder called Controllers in the root of the project.

  9. Create ValuesController.cs in the Controllers 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();
    }
    }
    }
  10. Run the application.

  11. Type "hi" in the textBox1

  12. Open browser and browse http://localhost:5000/api/values → You will see hi as response.

  13. http://localhost:5000/api/values/bye → You will see bye in textBox1

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



Leave a reply



Submit