Back in Chapter 3, we looked at various ways of optimizing DCOM for use over a seriously wide area network. If you remember, we had an order entry system located in Tierra del Fuego, and a client base in Ulaanbaatar. What I’d like to explore now is how we could bring MSMQ to bear on the problem.
One of the problems with DCOM (as presently implemented) is that it is entirely synchronous. Every time your client in Ulaanbaatar invokes a method in Tierra del Fuego, it has to sit and wait until the method completes until it can move on to the next operation. Most of the time this is pretty acceptable; however, every now and then, we come across an application that can’t wait — or perhaps doesn’t even need to wait. So the connection between the client and the server has to become a little looser.
For once, we find here that our old friend and rival CORBA has got there ahead of us. In the CORBA IDL definition, we can specify a method to have the attribute
. If you specify a method as having this attribute, the client doesn’t wait for the server to complete before moving on. A moment’s thought will tell you that if you specify a method as being oneway
oneway,
it can’t have any [out]
parameters, but that’s OK, because we can get outputs back from the server as events. This looks suspiciously like re-inventing asynchronous programming, callbacks and all, and frankly, it is. The current buzzword to describe this is Real-Enough Time.
Just to recap, our orders are represented by
objects, with – at the moment – a single interface, Order
. This interface has five properties, all strings: IOrder
, CustomerID
, Title
, Artist
and Label
. There is also a single method, Price
, which actually enters the order into a “database” Submit()
(actually a single-record file). What we’re going to do is implement all the properties as local methods (so that all validation is carried out locally), and then make the
method one-way asynchronous. We’ll use MSMQ queues to communicate between the client and the server, so what we’ll end up doing is serializing our orders somehow, encapsulating them as MSMQ messages, and then sending them over MSMQ to a queue located on the server. We’ll also need to set up some kind of stub process sitting on the server machine to take the messages off the queue as and when they come in.Submit()
Now we could do all of this by means of custom marshalling. If we did this, we’d probably end up implementing
in three places: in the COM server, in the proxy and also in the stub process. This ends up looking extremely inelegant, and there’s actually a much better way of doing it. It turns out that MSMQ is rather good at sending and receiving objects.IOrder
This is what we’re going to do. We’ll start off by creating a standard queue on each machine, called async. We’ll create a workspace called
, and add a project called AsyncOrder
underneath it. This project will start off like the AsyncOrder
project that we had in Chapter 3. However, this time, it’s implemented as a DLL. We'll also need to ensure that SerialOrder
is fully implemented, just as it was in the IPersistStream::GetSizeMax()
project. We'll take this as our starting point and examine the changes that need to be made from this point on.MarshalOrder
Later on, we’ll create a second project in the workspace, called
and then we’ll deal with the stub process. All of the code here can be downloaded from www.wrox.com. Right now, let’s concentrate on the DLL.AsyncOrderStub