This is a modified excerpt from chapter 17 "Networking Basics"
in Silverlight 5 in Action. You can thank James Manning (no
relation to the publisher) for this being in the book. Persistence
pays off :)
Shameless pimping: If you're looking for a one-stop shop for
learning Silverlight 5, consider my book Silverlight 5 in
Action, to be released in print near the end of this year. It's
currently in MEAP, with purchasers able to download chapters as I
make them available. Please, support my family, my children and buy
my book … ok, I'll be honest: Please, support my electronics,
robotics, CNC, woodworking, synthesis and other habits :)
For background, here's The HttpWebRequest/HttpWebResponse
listing 17.2 referred to from the Tasks portion of the chapter
public class RequestState
{
public WebRequest Request { get; set; }
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
InitiateWebRequest();
}
private void InitiateWebRequest()
{
string uri = "http://localhost:47498/helloWorld.xml";
var request = HttpWebRequest.Create(uri);
var state = new RequestState() { Request = request };
var asyncResult =
(IAsyncResult)request.BeginGetResponse(
new AsyncCallback(ResponseCallback), state);
}
private static void ResponseCallback(IAsyncResult asynchronousResult)
{
var state = (RequestState)asynchronousResult.AsyncState;
var request = state.Request;
var response =
(HttpWebResponse)request.EndGetResponse(asynchronousResult);
var stream = response.GetResponseStream();
var reader = new StreamReader(stream);
string xmlFileText = reader.ReadToEnd();
Debug.WriteLine("Status Code: " +
response.StatusCode);
Debug.WriteLine("Status Description: " +
response.StatusDescription);
Debug.WriteLine(xmlFileText);
}
}
17.1.1 Simplifying with Tasks
The Task Parallel Library (TPL) is a section of the full .NET 4
framework which includes the ability to manage asynchronous and
parallel operations. The subset of what is included in Silverlight
5 specifically targets the asynchronous part of the TPL, leaving
out the parallel bits for now.
The Task class exists in the System.Threading.Tasks namespace,
and is included as part of the runtime (no additional references
required. It's a core Silverlight feature. Like Rx, Tasks were not
created specifically to deal with networking, but they are very
useful in this space in Silverlight, especially when working with
HttpWebRequest and HttpWebResponse using the async request/response
pattern. The Task class is where all the goodness lies.
Taking the same project we created in listing 17.1 and 17.2 on
the request/response pattern, we can simplify the code using Tasks
as shown in listing 17.10
Listing 17.10 Using Tasks to handle asynchronous operations
private void InitiateWebRequest()
{
string uri = "http://localhost:47498/helloWorld.xml";
var request = HttpWebRequest.Create(uri);
var webTask = Task.Factory.FromAsync<WebResponse>(
request.BeginGetResponse, request.EndGetResponse, null)
.ContinueWith(
task =>
{
var response = (HttpWebResponse)task.Result;
var stream = response.GetResponseStream();
var reader = new StreamReader(stream);
string xmlFileText = reader.ReadToEnd();
Debug.WriteLine("Method: " + response.Method);
Debug.WriteLine("Status Code: " + response.StatusCode);
Debug.WriteLine("Status Description: " + response.StatusDescription);
Debug.WriteLine(xmlFileText);
});
}
Go back and look at listing 17.2 and compare the code to what we
have here. This is a significant reduction in code and number of
functions when compared to the original listing. The function that
makes that possible is the built-in Task.Factory.FromAsync method.
That function has knowledge of the async request/response pattern,
which just happens to be what is used by WebRequest and WebResponse
when making your networking calls.
In this listing, I start by creating the request just as we did
before. After that, however, I take a turn and instead of calling
any other request functions ourselves, I create a task. The task,
because it knows about the async pattern, needs only be provided
with the begin and end functions and, optionally, a state object.
Because we don't need to access the request ourselves, we're able
to get rid of the state object we had in the previous version of
this code.
When the task completes, the code in the .ContinueWith statement
is executed. This is what you can use to chain networking calls,
similar to what we did with Reactive Extensions, but arguably even
cleaner. In this example, I simply get the response stream and
display the XML file results to the debug window.
Just as was the case with Rx, this only scratches the surface of
what you can do with Tasks, and with the TPL in general.
Now, all this may seem like a little much for a "basics"
chapter, but it's important for you to understand that there are
ways to manage this whole async thing, that don't involve losing
all your hair and your sleep. I won't use Rx or Tasks in the
examples in this book as they are layers between you and learning
the fundamentals. However, in your real code, you'll almost
certainly want to turn to them for non-trivial networking
operations.
All of our examples so far have either used networking to a web
project in the same solution, or have eschewed networking
completely to simply simulate the asynchronous operations. Once you
start accessing services on other sites, you'll run into
cross-domain restrictions.
(the next section is on cross-domain networking and client
access policy settings)
Other great references for this topic: