Introduction
In this article i'm going to introduce the HttpClient assembly and explain to you how to make async requests in a command-line application.
The difficulty is in understanding how async works and why it doesn't work in a classic command line program because of the application Context.
All this article tips about GUI is provided for Visual Studio 2012.
Context
Most C# Applications have a UI context for managing async calls. They provide automatic event based manager for handling this kind of request. But in some other type of applications this Context is not defined by default. For example in command line based program, unit testing or windows services, there is no such concept. That's why you have to define it manually.
AsyncEx
Thanks for us, we are not the first ones to have such a problem. That's why the Nito AsyncEx was created. It's an easy to install assembly that allows you to define your how Context which will handle async calls in your application.
So, first of all, you need to install the package and to reference the assembly. Installing is done using NuGet package manager to easily install it, open the package manager console (located in Tools>Library Package Manager) and type :
PM> Install-Package Nito.AsyncEx
Next you have to add a reference to the assembly :
using Nito.AsyncEx;
So now that we have the Context Package we have to manually define an entry point with the newly created Context :
using Nito.AsyncEx;
namespace TestHttpClient
{
class Program
{
static void Main(string[] args)
{
try
{
AsyncContext.Run(() => MainAsync(args));
Console.ReadKey();
}
catch (Exception ex)
{
Console.Error.WriteLine(ex);
}
}
static async void MainAsync(string[] args)
{
}
}
}
So we have created our asynchronous context and now we can make asynchronous calls. Next we'll see how to use the System.Net.Http assembly for HTTP asynchronous calls.
Using the code
We'll see how to make a POST request because MSDN is filled with GET examples. But first of all, you have to add a Reference to the assembly in your project (Project>Add Reference...). Add the assembly to your used package too : using System.Net.Http;
To be more creative, in place of getting the body response to our request, I'll show you how to get a header field.
So, assuming we are in the MainAsync method that's how you can make a POST asynchronous request using HttpClient.
Dictionary<string, string> postArguments = new Dictionary<string, string>();
postArguments.Add("name", command);
try
{
HttpResponseMessage response = await this.httpClient.PostAsync(url, new FormUrlEncodedContent(postArguments));
response.EnsureSuccessStatusCode();
IEnumerable<string> Data = new List<string>();
if (response.Headers.TryGetValues("Server", out Data))
{
foreach( var d in Data)
{
Console.WriteLine(d);
}
}
return ret;
}
catch (Exception e)
{
Console.Error.WriteLine( e.ToString() );
}
And That's it.
Points of Interest
So now on, you can almost make a curl clone all asynchronous for best performances .
A remark about windows services. It's better to use a separate thread context for asynchronous calls. To do this, you have to use the AsyncContextThread method in your service start method :
protected async override void OnStart(string[] args)
{
var thread = new AsyncContextThread();
thread.Context.Queue(() => MyFunc(args));
thread.Start();
await thread.JoinAsync();
}
And now you can make your asynchronous service too .
History
2012.22.10 First version of this article