Geeks With Blogs
The Coding Bloke An ordinary bloke trying to keep up with the world of programming

In the previous post I droned on about how to apply the AsyncOperationService to an API conforming to the .NET Asynchronous pattern.  In this post I’ll be building a more real world example.  Well I say “real world” please don’t confuse that with something actually useful.  Its still a little contrived and is not an example of best practice but it is something you could actually build and test.

What are we going to build?

We are going to build an ambitious ground breaking Silverlight app that allows the user to enter part of a Stackoverflow user name and then searches for users based on the text entered.  Ok then <interlocks fingers, stretches arms forward palms facing out, knuckles crack> lets get started.

Create a new Silverlight Application in VS2010 and accept all the defaults so we have a host web application in the solution as well. 

The Contrived SearchUsers handler.

First we need to create in the web application a new “Generic Handler” item called “SearchUsers” (a file of type .ashx) that is going to access the Stackoverflow api on behalf of the Silverlight app.  The standard Stackoverflow API uses a “GET” request placing query parameters in the query string then returns results as JSON with gzip encoding.  Our “proxy” handler is going to instead accept a “POST” containing JSON and will return the inflated JSON response.   I did say it was a little contrived right?  Here is its code.

SearchUsers
    public class SearchUsers : IHttpHandler
    {
        public class Search { public string Filter { get; set; } }

        public void ProcessRequest(HttpContext context)
        {
            DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Search));
            Search search = (Search)ser.ReadObject(context.Request.InputStream);

            context.Response.ContentType = "application/json";
            context.Response.Charset = "utf-8";

            WebClient client = new WebClient();
            using (var result = client.OpenRead("http://api.stackoverflow.com/1.1/users?filter=" + Uri.EscapeDataString(search.Filter)))
            using (var inflated = new GZipStream(result, CompressionMode.Decompress))
            {
                inflated.CopyTo(context.Response.OutputStream);
            }
        }

        public bool IsReusable { get { return false; } }
    }

 

Lets just get the UI and other bits and pieces out of the way

The project is going to need the code for the core AsynchronousOperationService and the FromAsyncPattern method from previous blog articles.  You’ll note that I use a partial class so I don’t have to come up with a new class name to extend the service features.  Place the code from these code blocks in separate files or merge them together into one.

For the UI we just need a TextBox to enter the filter text, a “GO” button and ListBox to display the results.  Paste over the LayoutRoot of the MainPage.xaml with the folllowing code.

LayoutRoot of MainPage.xaml
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <TextBox x:Name="txtSearch" />
            <Button x:Name="btnSearch" Content="Go" Grid.Column="1" Click="btnSearch_Click" />
        </Grid>
        <ListBox x:Name="lstResults" Grid.Row="1" />
    </Grid>

 

The now obligatory imaginary bit

So now we want to write a method on the client which posts some JSON to the server containing filter text taken from the txtSearch text box and having received the JSON response display the results in the list box.  We are going to use HttpWebRequest to do that.  In WPF we could write all this code synchronously and it would look like the following (note: even though it is possible in WPF it still isn’t a good idea).

GetSearchResults Synchronous
        private List<string> GetSearchResults(string filter)
        {
            WebRequest req = WebRequest.Create(new Uri(Application.Current.Host.Source, "/SearchUsers.ashx"));
            req.Method = "POST";

            Stream reqStream = req.GetRequestStream();

            using (reqStream)
            {
                WriteFilterToStream(filter, reqStream);
            }

            WebResponse response = req.GetResponse();

            return GetUserNamesFromWebResponse(response);
        }

        void WriteFilterToStream(string filter, Stream stream)
        {
            JsonObject search = new JsonObject();
            search["Filter"] = filter;
            search.Save(stream);
        }

        List<string> GetUserNamesFromWebResponse(WebResponse response)
        {
            using (var stream = response.GetResponseStream())
            {
                JsonObject results = (JsonObject)JsonObject.Load(stream);
                return ((JsonArray)results["users"])
                    .Cast<JsonObject>()
                    .Select(jo => (string)jo["display_name"]).ToList();
            }
        }

 

Just paste the above code into MainPage.xaml.cs. Now before the MVVM police come and duff me up, let me just state I’m putting this code there for brevity, in real world code you would not be placing code like this in code-behind (actually I might if it suited me, I can be a bit of a non-conformist).

Of course this doesn’t work.  Visual Studio places redlines under GetRequestStream and GetResponse because WebRequest in Silverlight doesn’t have these methods.  In Silverlight we only have the asynchronous pattern to work with BeginGetRequestStream/EndGetRequestStream and BeginGetResponse/EndGetResponse.  We need to convert GetSearchResults into a method that can be run by AsyncOperationService and use the FromAsynPattern method to create AsyncOperation instances from these pairs of methods.

Creating WebRequestExtensions

Before transforming the GetSearchResults method we will introduce an extensions class for the WebRequest that wraps up the use of FromAsyncPattern.  This will help with code readability.   Add a new class to the project called WebRequestExtensions.cs and place the following code in it.

WebRequestExtensions.cs
using System;
using System.Net;
using CodingBloke.AsyncOperations;
using System.IO;

namespace CodingBloke.AsyncOperations
{
    public static class WebRequestExtensions
    {
        public static AsyncOperation GetRequestStreamAsyncOp(this WebRequest request, Action<Stream> returnResult)
        {
            return AsyncOperationService.FromAsyncPattern(request.BeginGetRequestStream, ar => returnResult(request.EndGetRequestStream(ar)));
        }

        public static AsyncOperation GetResponseAsyncOp(this WebRequest request, Action<WebResponse> returnResult)
        {
            return AsyncOperationService.FromAsyncPattern(request.BeginGetResponse, ar => returnResult(request.EndGetResponse(ar)));
        }
    }
}

 

Now replace the GetSearchResults method with the follow transformed version and include in the MainPage.xaml.cs a using for CodingBloke.AsyncOperations.

GetSearchResults Asynchronous
        private IEnumerable<AsyncOperation> GetSearchResults(string filter, Action<List<string>> returnResult)
        {
            WebRequest req = WebRequest.Create(new Uri(Application.Current.Host.Source, "/SearchUsers.ashx"));
            req.Method = "POST";

            Stream reqStream = null;
            yield return req.GetRequestStreamAsyncOp(r => reqStream = r);

            using (reqStream)
            {
                WriteFilterToStream(filter, reqStream);
            }

            WebResponse response = null;
            yield return req.GetResponseAsyncOp(r => response = r);

            List<string> result = GetUserNamesFromWebResponse(response);

            returnResult(result);
        }

This code satisfies my goal of having the asynchronous code looking very similar to the synchronous version.  Functions that originally retuned a value now simply call a lambda to provide the return value.  Other than that this code is identical to the synchronous version.

Finally wire up the button

To complete the code that “should” (assuming I’ve explained every thing well enough) make this code executable and operational place this final snippet in the MainPage.xaml.cs.

        private void btnSearch_Click(object sender, RoutedEventArgs e)
        {
            List<string> result = null;
            GetSearchResults(txtSearch.Text, r => result = r).Run((err) =>
            {
                if (err == null)
                {
                    lstResults.ItemsSource = result;
                }
                else
                {
                    MessageBox.Show("Oops something bad happened");
                }
            });
        }

 

This final snippet exemplifies another of my goals for AsyncOperationService.  The error handling story is robust.  Normally in production quality code you would have to ensure that all your callback/event methods catch and do appropriate things with any exception.  You would then need to communicate with anything else waiting for a callback that what was expected to happen hasn’t due to an error.

Whilst AsyncOperationService doesn’t eliminate all of that burden (if you peek back to the previous article you can see that FromAsyncPattern catches all errors) the pattern allows the sequence to be terminated and error be reported to a single high level point.  The code that actually does things we are interested in (the GetSearchResults in this case) still looks quite simplistic as if it needs further error handling yet it doesn’t, it is complete.

What’s next?

In my next article on the AsyncOperationService I’m going to apply similar techniques to making WCF calls.

Posted on Saturday, September 10, 2011 2:46 PM Silverlight , AsyncOperationService | Back to top


Comments on this post: The AsyncOperationService and HttpWebRequest

# How to login through in irctc.co.in through httpwebrequest class
Requesting Gravatar...
Please send me C# Application Form Code.

Thank You Sir.
Left by Abhishek on May 31, 2016 2:57 PM

Your comment:
 (will show your gravatar)


Copyright © codingbloke | Powered by: GeeksWithBlogs.net