Showing posts with label Web API. Show all posts
Showing posts with label Web API. Show all posts

Thursday, May 3, 2012

Async III: Cancellation

The previous posts in this series talked about the basics of async and exception handling. In this post we will take a look at cancellation and the beginnings of progress reporting.

For cancellation you can make use of a CancellationToken. This is an extra parameter that can be send to an asynchronous method call, most asynchronous methods you find in the .NET framework provide an overload with cancellation. You can extend your own asynchronous methods as well to take in a CancellationToken.

For progress reporting the IProgress interface can be used. This interface defines a Report method that can be used to report progress from within an asynchronous method. Asynchronous calls again can define overloads that take in a IProgress interface.

Let's first take a look at cancellation.

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
    cts = new CancellationTokenSource();

    try
    {
        await _restCaller.PublishHikeRequest(cts.Token);

        var driverIds = await _restCaller.GetDrivers(cts.Token);

        if (driverIds != null)
            await ShowDriversOnMap(driverIds, cts.Token,
                new Progress<int>(p => statusText.Text = string.Format("{0} of {1}", p, driverIds.Count)));

        var hikerIds = await _restCaller.GetHikers(cts.Token);

        if (hikerIds != null)
            await ShowHikersOnMap(hikerIds, cts.Token);

    }
    catch (OperationCanceledException exc)
    {
        statusText.Text = exc.Message;
    }
}

As you can see, I added a datamember cts of type CancellationTokenSource to my class. A CancellationTokenSource gives you a CancellationToken through its Token property. This token can be send along to all you asynchronous methods. Once the operation gets cancelled, each asynchronous method using the token will be notified of cancellation. The result of cancellation will be an OperationCanceledException that you can catch.

Cancelling an operation is as simple as calling Cancel on the CancellationTokenSource.

protected void Cancel_Click(object sender, RoutedEventArgs e)
{
    if (cts != null)
    {
        try
        {
            cts.Cancel();
        }
        catch (AggregateException exc)
        {
            exc.Handle((ex) => {
                return true;
            });
        }
    }
}

The AggregateException I catch here, is necessary since the REST calls in the RestCaller class tend to throw additional exceptions on cancellation (this only happens occasionally). I just swallow these kinds of exceptions, since they don't add any important information.

The nice thing about cancellation is that you can have it bubble down in your code. I create the CancellationToken in the top layer of my appllication, but it's send along to different methods, which again can send it to other asynchronous methods they call. For instance the GetDrivers method sends it along with its asynchronous REST call.

public async Task<List<Guid>> GetDrivers(CancellationToken token = default(CancellationToken))
{
    List<Guid> drivers = null;

    try
    {
        var client = new HttpClient();
        var request = new HttpRequestMessage();
        request.Headers.Add("Accept", MESSAGE_TYPE);
        request.RequestUri = new Uri(string.Format("{0}/Hiker/{1}/DriverIdsNearby", BASE_URL, MY_ID));
        var response = await client.SendAsync(request, token);
        response.EnsureSuccessStatusCode();
        var content = await response.Content.ReadAsStringAsync();
        drivers = await JsonConvert.DeserializeObjectAsync<List<Guid>>(content);
    }
    catch (HttpRequestException exc)
    {
        var dialog = new MessageDialog(exc.Message);
        dialog.ShowAsync();
    }

    return drivers;
}


This makes it very easy to cancel something. Whatever your code is executing at the moment, it gets cancelled.

In the next post we will look at progress reporting.

Wednesday, May 2, 2012

Async II: Exception Handling

In the previous blog post, we looked at the basics of async. In this post, we will look at exception handling. You need exception handling the moment something goes wrong in an asynchronous call. When this happens, the Task that comes out of the asynchronous call will have an error status and you won't be able to get the result from the method.

Handling these kinds of error situations is actually really simple. The only thing you need to do is wrap your asynchronous call in a try - catch statement, just like you would do with synchronous code. Let's take a look at an example:

public async Task PublishHikeRequest()
{
    var hikeRequest = GetHikeRequest();

    try
    {
        var client = new HttpClient();

        var url = string.Format("{0}/HikeRequest", BASE_URL);
        var response = await client.PostAsync(url, await BuildJsonContent(hikeRequest));
        response.EnsureSuccessStatusCode();
    }
    catch (Exception exc)
    {
        var dialog = new MessageDialog(exc.Message);
        dialog.ShowAsync();
    }
}

This method can be found in the RestCaller class, the one that's being used in the OnNavigatedTo from the previous blog post. In this method we post a message to a REST service in an asynchronous way. There are a couple of points where this code can give us error situations. The REST service can be down or for some reason our Json message can't be build as expected. For this we use a try catch clause to wrap the asynchronous calls.

Simpler than this, they can't make it for you. I just want to point out one more thing. Don't do as I did and show a MessageDialog in your catch clause. I just put it there for demoing purposes, but it can really bite you in the butt. Let me explain: If the REST service is down, it will take a while for the timeout of the call, giving a HttpRequestException, to kick in (this is about one minute). By this time, it is very well possible that the user of your application has already performed 10 other actions. The MessageDialog will only get him confused, because it's a reaction to an action he performed a minute ago. For this it is important that you know how to cancel actions that were kicked off, but are no longer relevant in the current user context.

That is why, in the next blog post, we will look at cancellation (and progress reporting).

And just another small thought on asynchronous calls I want to add. After the Visug session I got a question asking if you don't need to keep track of your background threads and if in the PublishHikeRequest method I can do stuff with my UI (for instance alter text in a TextBox). The answer is: yes you can. Your code actually executes synchronously until you get an await. This means all code in PublishHikeRequest is synchronous up until the PostAsync call. This is a framework call that actually does some stuff with threadpools or async I/O. But we don't need to worry about that. All of our code is still synchronous. And the callback that is being build for us, with the rest of our message body, will again be called on the UI thread. So, to sum up, nothing to worry about, go ahead and alter the text of that TextBox.

Friday, April 13, 2012

JSON POST with ASP .NET Web API

I have been struggling a bit with porting existing Json calls to the new ASP .NET Web API framework. I actually got the GET request working pretty quickly, but it were the POST (and DELETE en PUT) requests that were giving me headaches. Problem is the current brevity and lack of practical examples for the Web API framework. So here goes a short example of getting a Json POST up and running.

For these examples I used the Visual Studio 2011 beta version.

Let's first start with the GET request. What you need for this is the HttpClient class, which can be found in the System.Net.Http namespace. This class provides methods like GetAsync, PutAsync, DeleteAsync and PostAsync. The 'Async' extensions let you know that you can use the new async and await keywords to get this up and running. A GET requests with the HttpClient consists of only two lines of code.

var client = new HttpClient();
var response = await client.GetAsync("http://some_url/resource_name/resource_id");
response.EnsureSuccessStatusCode();

All of this is contained in a method that has the extra async keyword. I also added the EnsureSuccessStatusCode call to verify my call to the REST service didn't fail. If the call fails the EnsureSuccessStatusCode will throw an exception. So you can easily wrap this piece of code in a try catch block.

So, that was quite easy. The GET call should work immediately.

On to the POST call. I actually want to post an object to our REST service. The previous version of the code I was porting to the Web API used the RestSharp (performs REST calls) and NewtonSoft.Json  (serializes from and to Json) frameworks to perform REST calls (both are available via NuGet). I started out reusing only NewtonSoft.Json, since the HttpClient class removes the need for the RestSharp framework. But is turned out I couldn't get the serialized Json object send to the service in a acceptable format. The service kept giving me 400 Bad Request messages. So I was doing something wrong.

After some searching I found there are a couple of different content class types you can use when performing a PostAsync. I used StringContent up untill then, but I needed a ObjectContent. The HttpRequestMessage class can create one for you. Moreover, the Web API contains its own Json formatters, so the need for the NewtonSoft library became obsolete.

var anObject = new MyObjectType
{
    SomeProperty = "some value"
};

try
{
    var client = new HttpClient(); 
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var requestMessage = new HttpRequestMessage();
    var content = requestMessage.CreateContent&lt;MyObjectType>(
        anObject,
        MediaTypeHeaderValue.Parse("application/json"),
        new MediaTypeFormatter[] { new JsonMediaTypeFormatter() },
        new FormatterSelector());

    var response = await client.PostAsync("http://some_url/resource_name", content);
    response.EnsureSuccessStatusCode();
}
catch (Exception exc)
{
    Console.WriteLine(exc.Message);
}


And there you have it, my first successful Json POST message.