HttpWebRequest Fundamentals - Windows Phone Services Consumption - Part 2

wp7services-httpwebrequest

This is the second part of our "Consuming Services with Windows Phone" series. Previously we covered using WebClient to pull raw HTML from the web. WebClient isn't the most optimal solution for all things webbie, so let's explore the daddy of WebClient, HttpWebRequest.

HttpWebRequest is a lower-level abstraction of the http protocol than WebClient. WebClient actually wraps HttpWebRequest.  HttpWebRequest allows for more direct access of HTTP aspects which WebClient does not.  Things such as the Accept header, Content Length and Type, direct access to Cookies and the User Agent.

WebRequest also returns on a background thread, allowing a program to parse and process results as they are returned without crunching down the main UI. When a program wishes to update the main UI  in a callback from a HttpWebRequest, the program must use the Dispatcher to process user interface updates, since the WebRequest callback is on the background thread.

If you wish to explore the basics of a HttpWebRequest for scraping a website, walk through the steps below.

Step1: Create a new Windows Phone Portrait Project
Step2: Modify MainPage.xaml, change the ContentPanel from a Grid to StackPanel, and make it match what's below.

         <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Button Content="Call HttpWebRequest" Width="250" Click="Button_Click" />
            <TextBlock Text="HttpWebRequest Target:" Style="{StaticResource PhoneTextNormalStyle}" Foreground="{StaticResource PhoneAccentBrush}" />
            <TextBlock Text="https://msdn.microsoft.com" TextWrapping="Wrap" Margin="20,0,0,0" x:Name="TextBlockTargetUri" />

            <TextBlock Text="Elapsed Time:" Style="{StaticResource PhoneTextNormalStyle}" Foreground="{StaticResource PhoneAccentBrush}" />
            <TextBlock Text="tbd" TextWrapping="Wrap" Margin="20,0,0,0" x:Name="TextBlockElapsedTime" />

            <TextBlock Text="HttpWebRequest Call Results:" Style="{StaticResource PhoneTextNormalStyle}" Foreground="{StaticResource PhoneAccentBrush}" />
            <TextBlock x:Name="TextBlockResults" Text="results go here" Margin="20,0,0,0" TextWrapping="Wrap"/>
        </StackPanel>

Next the code. Match up the steps given to the code block below.

Step3: Wire up the Button_Click handler.  In the handler we setup a HttpWebRequest against our target Uri, then initiate the request with a callback targeted towards our "ReadRequestCallback" handler.
Step4:  Code up our handler for the WebRequestCallback. First we'll create a new request instance. Then initialize an HttpWebResponse we can use to pull the results down from the web. After that we'll use a StreamReader to read the data. Once the data is down, since HttpWebRequest returns on a non-UI thread, we just use Dispatcher.Update to show the data in the UI.  Run the program and you should see results similar to what's above.

     public partial class HttpWebRequestPage : PhoneApplicationPage
    {
        public HttpWebRequestPage()
        {
            InitializeComponent();
        }
  // STEP3 STEP3 STEP3
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            System.Uri targetUri = new System.Uri(TextBlockTargetUri.Text);
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(targetUri);
            request.BeginGetResponse(new AsyncCallback(ReadWebRequestCallback), request); 
        }

    // STEP4 STEP4 STEP4
        private void ReadWebRequestCallback(IAsyncResult callbackResult)
        {
            HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.EndGetResponse(callbackResult);

            using (StreamReader httpwebStreamReader = new StreamReader(myResponse.GetResponseStream()))
            {
                string results = httpwebStreamReader.ReadToEnd();
                //TextBlockResults.Text = results; //-- on another thread!
                Dispatcher.BeginInvoke(() => TextBlockResults.Text = results);
            }
            myResponse.Close();
        }
    }

Try this. Comment out the Dispatcher.BeginInvoke line and uncomment the TextBlockResults.Text line. Run the program. Now the background thread the callback is running on is trying to update the UI directly. Directly hitting the UI from a background thread results in an System.UnauthorizedAccessException: Invalid cross-thread access. Something to watch out for, definitely!

All in all, HttpWebRequest provides a greater flexibility than WebClient by being able to address http headers more directly. Since the thread returns on a non-UI thread, there's also a greater opportunity to boost performance and give a better user experience. The pattern isn't as simple as WebClient, but its not too onerous either.

I'll have another post up soon with some service consumption examples against some real world endpoints. See you then.

Consuming Windows Phone Services Series
Part 1 - Web Client Basics - https://blogs.msdn.com/b/devfish/archive/2011/04/06/webclient-windows-phone-services-consumption-part-1.aspx
Part 2 - HttpWebRequest Fundamentals - https://blogs.msdn.com/b/devfish/archive/2011/04/07/httpwebrequest-fundamentals-windows-phone-services-consumption-part-2.aspx
Part 3 - Parsing REST based XML Data - Part A - Single Result - https://blogs.msdn.com/b/devfish/archive/2011/05/05/consuming-geocode-yhoo-api-via-rest-windows-phone-services-consumption-part-3.aspx
Part 4 - Parsing REST based XML Data - Part B - Multiple Results - https://blogs.msdn.com/b/devfish/archive/2011/05/10/consuming-geocode-yhoo-api-via-rest-dealing-with-multiple-results-part-4.aspx