torsdag, april 11, 2013

Asynchronous HTTP requests using Ramone

Ramone (my C# web API and REST client) now supports asynchronous HTTP request :-) This has taken quite a while for me to implement due to a large amount of automatic tests for the the async request handling. But now its there and I hope some of you will find it useful in your applications.

Asynchronous requests can be prepared via a call to Async() on the Request object. After this you can do the actual request using any of the GET, POST, etc. methods where a callback delegate is passed as on of the arguments. When the request completes it will call back to the delegate, passing in the response from the request.

Here is one example:
// Define resource type
public class Cat
{
  public string Name { get; set; }
  public DateTime DateOfBirth { get; set; }
}

// URL template (relative to service root)
const string CatUrlTemplate = "/cat/{name}";

public static void GetAsync()
{
  // Create session pointing to service root
  ISession Session = RamoneConfiguration.NewSession(...));

  // Setup HTTP request
  Request req = Session.Bind(CatUrlTemplate, new { name = "Mike" });

  Console.WriteLine("Waiting for request to finish ...");

  // Initiate asynchronous request
  req.AcceptJson().Async()
     .Get<Cat>(response =>
       {
         Console.WriteLine("Cat: {0}.", response.Body.Name);
         Console.Write("Press Enter to complete: ");
       });

  Console.ReadLine();
}
It is also possible to register a callback delegate for error handling; if anything goes bad with the request (or if the operation callback delegate raises an exception) then this error delegate will be called.

In the same way it is possible to register a callback delegate to be called after the request has been completed. This delegate will always be called no matter what the outcome of the operation is.

Building on the previous example, we can now include the two OnError and OnComplete handlers:
// Initiate asynchronous request with additional handlers
req.AcceptJson().Async()
   .OnError(e => Console.WriteLine("Failed: {0}", e.Exception.Message))
   .OnComplete(() => Console.Write("Press Enter to complete: "))
   .Get<Cat>(response =>
     {
       Console.WriteLine("Cat: {0}.", response.Body.Name);
     });
POST, PUT and other operations usually includes a body in the request. This can easily be added as a parameter in the asynchronous operation methods:

// Initiate asynchronous POST including a request body
var body = ... any data object to POST ...
req.AcceptJson().Async()
   .Post<Cat>(body, response =>
     {
       Console.WriteLine("Cat: {0}.", response.Body.Name);
     });
Ramone will also handle redirects, authentication and all the other standard synchronous stuff when going asynchronous.

Have fun :-)