This post is part of a series about WCF extensibility points. For a list of all previous posts and planned future ones, go to the index page.
This is the part 3 of 3 of a “mini-series” inside the main series. For the other parts, here’s the list.
Just like we did on the previous post, let’s jump right back into the scenario (for a scenario description, go back to the part 1). After the detour through the service model, we’ll dive back to the transport channel, to implement the asynchronous support for the request channel used to consume the service. I’ll also share some ideas for testing such operations.
At the previous post, we had a transport channel plus an endpoint behavior, which, together, could be used to call a simple JSON-RPC service. Now, let’s finish the implementation of the request channel with support for asynchronous requests. This is important in scenarios such as when that transport is to be used in UI threads (so we don’t block that thread and make the application “hang” while the request is being made), or in platforms such as Silverlight, in which synchronous networking requests simply don’t exist.
Since we’re going to enter the asynchronous world, testing each part of the communication as it’s implemented is really important. I’ve made the mistake in the past of trying to implement all the asynchronous operations, then trying to use it within a WCF channel. Things would blow up in a worker thread, and tracking down what was going on after all the asynchronous callbacks wasn’t something fun. So I strongly recommend to have some sort of unit test framework which can be used to validate the individual pieces of the system. I’d usually go with MSTest (the unit test framework which comes with Visual Studio), but since at home I use the express editions and it’s not supported, I decided to go with xUnit (one I’m use to and it’s free / open source; others would also be good) for this.
But before going further, here goes the usual disclaimer: this is a sample for illustrating the topic of this post, this is not production-ready code. I tested it for a few contracts and it worked, but I cannot guarantee that it will work for all scenarios (please let me know if you find a bug or something missing). I really kept the error checking to a minimum (especially in the “simple service” project and in many other helper functions whose inputs should be sanitized, such as the reflection helper), to make the sample small (or as small as a fully synchronous and asynchronous transport channel can be). Also, the timeout handling in this sample is far from ideal (in some cases they’re simply ignored, in other they’re interpreted very liberally).
So before I even attempted to write the first asynchronous operation, I started a simple unit test project. And since most of the operations (and the base class itself) were private / internal, I used a simple reflection helper to test the internal methods, as shown below.
In order to test the socket operations, I also wrote a simple socket server which simply returned whatever data was sent to it (according to the same framing protocol, 4-byte length + data, as the transport channel), to validate our client implementation. I’ll leave the simple server out of this post, but it is in the code from the gallery. Also, to test socket operations we need both send / receive, so to have a starting point for the test, the first test I wrote didn’t use anything asynchronous at all, was a simple synchronous send/receive (it was useful to test my simple server as well).
Having that test ready gave me more confidence that the synchronous operations were working, so I could start testing the asynchronous ones individually (i.e., first test / implement the asynchronous Send, and test it with the synchronous receive, which I “knew” was working). And here goes the first test prior to the implementation (in a TDD fashion which I should have used from the start, but that’s another story). The test is exactly like the previous one, but the SocketSend method is split in a Begin/End pair. A simple event is used to wait in the main thread until the asynchronous part is done.
And we can now finally start implementing the operations. First, [Begin/End]SocketSend. As will be the pattern in all the implementations here, we’ll create a new class which implements IAsyncResult (actually, a class derived from the helper class AsyncResult, shown in the first post, which in turn implements that interface). And that class will be the one which will do all the work.
The SocketSendAsyncResult class is show in its entirety below. Right at its constructor (after storing some variables), we start the asynchronous operation (via the StartSending) method. In StartSending, we call the Socket.BeginSend to start that. One thing which is often overlooked is that asynchronous operations can actually be completed synchronously, so to prevent race conditions between chained asynchronous calls, it’s recommended that we check that and take different actions based on that. If it’s a “normal” asynchronous operation, we simply return and wait for the callback; otherwise we go into the CompleteSend function to see if the sending is completed, and complete the AsyncResult itself if it’s the case. Otherwise, we start sending it again. On CompleteSend, we need to see if all the bytes which we asked the socket to send were actually sent; if not, we need to start sending again from the point where we stopped. In the asynchronous case, the callback is invoked when the socket operation is complete (it’s also invoked if the operation completed synchronously, but since we already dealt with that case, the first thing in the operation is to check that and return if that’s indeed the case). In the callback we take a similar path as in the “completed synchronously” case: call CompleteSend to see if all bytes were indeed sent, and if not, start sending again.
If you didn’t understand that class, please go back and look at it again. Classes like that will show up a lot over the next paragraphs…
So after validating that the unit test works (I had to fix a few things myself), so that was already a good thing to have those, on to the next operation: socket receive. Just like the socket send case, I’ll start with a unit test to validate it, using the synchronous send operation (which is a lot less error-prone than its asynchronous counterpart).
And the pattern continues. The Begin/End operations are fairly simple, just delegating the bulk of the work to the new class derived from AsyncResult.
Like on the previous AsyncResult class, the SocketReceiveAsyncResult starts off by storing some internal data, then firing off the socket request. Whether the request completed synchronously or not, the method CompleteReadBytes is called (by the constructor or the OnReadBytes callback, respectively). There we check whether the requested number of bytes has already been read. If that’s the case, we complete the result (which causes the client callback to be called). Otherwise we ask for more bytes in another BeginSocketReceive call.
And now that the base operation is done, we can move onto the functions which call it. And that’s essentially the pattern for writing out asynchronous channels. Start from the bottom, and build up the stack until the function which we need (in this case [Begin/End]Request from the IRequestChannel interface). Next up, WriteData and ReadData. The first one, however, is fairly simple – it doesn’t need to iterate, doesn’t need to call multiple asynchronous requests, it simply needs to add the length to the buffer (a synchronous operation), and then send the bytes. So for this case, we don’t need to create a new AsyncResult implementation, simply chaining the call directly after modifying the input, as shown below.
Reading data, however, goes back to the asynchronous chain. To read a properly framed request, we need to make two read calls: one for the 4-byte length, and one for the actual data (all as cascading asynchronous calls). So we do need a new AsyncResult class at this time.
The ReadDataAsyncResult goes like the previous ones. The constructor initializes some variables, then makes the first asynchronous call (to receive the 4 length bytes). When that operation completes (on CompleteDrainLength), the object makes the second asynchronous call (to receive the actual bytes), and finally when that is done, the AsyncResult completes itself, saving the data read in an instance variable to be returned in the End call.
So at this point we’re done with the “base” operations (those dealing with sockets only), and can start moving on to the channel operations themselves (those which deal with the Message type): SendMessage and ReceiveMessage. Those are quite similar: Send first encodes the Message into the data bytes, then writes the data to the wire; Receive first reads data from the wire, then decodes them into a Message. This is similar to the WriteData operation: a combination of one synchronous and one asynchronous operation. So thankfully we don’t need another AsyncResult class for those. As with the other operations, I also have unit tests for those, but I’ll skip them here (they’re in the code gallery download).
And now all the basic operations are done. All we need now is to (finally!) implement the Begin/End request operations, in the request channel itself. A request operation is a simple pair of Send/Receive calls (i.e., two asynchronous calls), so we need, yes, a new AsyncResult class to handle this case. First the methods themselves, trivial:
And the RequestAsyncResult class. As usual, the constructor calls the first asynchronous operation (Send), and when it’s complete (synchronously or not), the completion of the operation calls the second operation (Receive).
And finally the request asynchronous operation is complete. For this case, it’s actually interesting to show the unit test. Although the class is internal (so we need to use the reflection helper to instantiate it), we know that the type inherits from ChannelBase and implements IRequestChannel, so we can use those public types to write the tests in a cleaner way.
So are we done? Not quite. Notice that opening the channel actually involves some networking calls (first get the IP address of the server from the name, a DNS call, then connect the socket to the server, with the TCP handshaking). So we need to override the asynchronous open calls (BeginOpen and EndOpen) to make sure that we don’t block the calling thread. And since we’re dealing with at least two asynchronous calls… you know the drill by now.
And the ConnectAsyncResult class. Notice that a machine may have multiple IP addresses, so we need to account for that when trying to connect the socket.
Now, we’re finally done! Now for the client application to test it. An asynchronous interface (which can be typed if the endpoint is using the behavior we implemented in the previous post) gives us the starting point for testing it.
And using that interface in a program to verify that it worked (which, in my case, it did, since I had fixed the errors while creating the unit tests).
And now, we’re really, really done. Here’s a recap of this “mini-series”:
Next up, a different kind of channel – let’s move to the server side with an IReplyChannel.
[Code in this post]
[Back to the index]