Adding Code to Components

Although we’ve by no means covered all the objects, properties, methods and events available in MSMQ in the previous section, we now have enough information to start using MSMQ in our own applications. In the next chapter, you'll see how we implemented MSMQ in our Wrox Car Co sample application. In the meantime, to give you a gentle introduction, we'll add some MSMQ features to the Finance component that we started creating way back in Chapter 2.

A Finance Component With Messaging

In Chapter 2 we created a component named WCCFinance.PaymentTerms, which could be used to calculate the number of payments required to clear a loan at a fixed monthly interest rate. In today's world of close scrutiny on financial institutions, it's usual to be required to keep records of all credit advice you give to customers. To comply with this, we want our component to be able to log all the calculations it does.

Logging Credit Calculations

Of course the easy place to log them is in a text file on the local machine. However, it makes more sense for our head office to log all quotations from all the company's branches. To do this we have to find a way of sending each calculation off to head office. We could do it in daily batches, but MSMQ seems to offer the opportunity to do it in (almost) real time. We can create a message for each calculation and send it off to head office via MSMQ.

Using MSMQ has another advantage. If we were accessing the head office database using an OLE-DB or ODBC driver directly, our component would be stalled while waiting for the operation to complete—especially if the network was running slowly that day. And if the network was down altogether, we wouldn’t be able to do any calculations at all.

The User Interface

The user interface doesn’t change from the earlier examples. It just submits the values to an ASP script. To do so, it uses a <FORM> with three HTML text boxes and a SUBMIT button. Here's the <FORM> code again:

<FORM ACTION="financeMQ.asp" METHOD="POST">
Total Price ($): 
<INPUT TYPE="TEXT" NAME="txtTotalPrice"><BR>
Interest Rate (%): 
<INPUT TYPE="TEXT" NAME="txtInterestRate"><BR>
Monthly Payment ($): 
<INPUT TYPE="TEXT" NAME="txtMonthlyPayment"><P>
<INPUT TYPE="SUBMIT" VALUE="Submit to ASP script">
</FORM>

And here's what it looks like in the browser:

The Active Server Pages File

The page that processes the values sent from the browser is the main business rules component for our application. It calls the PaymentTerms component to carry out the calculation, and returns the results by writing them into the HTML page that it creates and sends back to the browser. The initial section of this code is the same as we used in Chapter 2:

<%@ LANGUAGE="VBSCRIPT" %>

<HTML>
<HEAD>
<TITLE>Results from the WCCFinance Component</TITLE>
</HEAD>
<BODY>

<% 
Set objFinance = Server.CreateObject("WCCFinance.PaymentTerms")
objFinance.TotalPrice = Request.Form("txtTotalPrice")
objFinance.InterestRate = Request.Form("txtInterestRate")
objFinance.MonthlyPayment = Request.Form("txtMonthlyPayment")
intResult = objFinance.GetNumberPayments
Set objFinance = Nothing

If intResult > 0 Then %>

A total price of <B>$<% = Request.Form("txtTotalPrice")%></B> 
at a monthly interest rate of <B><% = Request.Form("txtInterestRate")%>%</B>,
and paying <B>$<% = Request.Form("txtMonthlyPayment")%></B> 
per month, will require <B><% = intResult %></B> payments.<P>

<% Else %>

Sorry, a monthly payment of 
<B>$<% = Request.Form("txtMonthlyPayment")%></B> 
is not sufficient to pay off a loan of 
<B>$<% = Request.Form("txtTotalPrice")%></B> 
at an interest rate of 
<B><% = Request.Form("txtInterestRate")%>%</B><P>

<% End If
...

The Message Queue Code

At this point in the script, we've got the results and written them into the returned page. All we need to do now is send them off to head office as well. We'll do the easy bit first and create the message body:

'create the message to send to head office
CRLF = Chr(13) & Chr(10)
strMsgBody = "Finance quote offered on " _
           & FormatDateTime(Now, vbGeneralDate) & CRLF _
           & "Total Price: " _
           & FormatCurrency(Request.Form("txtTotalPrice")) & CRLF _
           & "InterestRate: " _
           & Request.Form("txtInterestRate") & "%" & CRLF _
           & "Monthly Payment: " _
           & FormatCurrency(Request.Form("txtMonthlyPayment")) & CRLF _
           & "Number of Payments Required: " & CStr(intResult) & CRLF
...

Now we can create an instance of the MSMQQueueInfo object that we’ll use to define (and if required create) our queue. The PathName includes the name of our head office machine:

...
'create a queue info object and set the path and name
Set objQueueInfo = Server.CreateObject("MSMQ.MSMQQueueInfo")
objQueueInfo.PathName = "daisy\FinanceQueue" 'remote head office queue
...

Next we attempt to create the queue. The On Error Resume Next statement will prevent the error that will occur if the queue already exists from breaking our code:

...
'try and create the queue in case it doesn’t already exist
On Error Resume Next
objQueueInfo.Create
...

The next step is to open the queue. The MSMQQueueInfo object's Open method returns an MSMQQueue object, and we can set the values of the two constants we need (remember, ASP doesn’t recognize the MSMQ named constants):

...
'use the MSMQQueueInfo object to open the FinanceQuote queue 
Dim objQueue
MQ_SEND_ACCESS = 2   'declare the 'send' and 'deny' constants
MQ_DENY_NONE = 0     
Set objQueue = objQueueInfo.Open(MQ_SEND_ACCESS, MQ_DENY_NONE)
...

Finally, providing the queue was opened successfully, we can create our new MSMQMessage object and set its properties before calling its Send method. We're only using a low priority for this logging operation. The last step is to close the queue, write a message into the returned page, and add the closing HTML stuff:

...
'see if queue opened OK, and if so create and send message
If objQueue.IsOpen Then
  Set objMessage = Server.CreateObject("MSMQ.MSMQMessage")
  objMessage.Priority = 2
  objMessage.Label = "Finance Quote on " _
                   & FormatDateTime(Now, vGeneralDate)
  objMessage.Body = strMsgBody
  objMessage.Send objQueue
  objQueue.Close
  Response.Write "Quote details also logged at head office."
Else
  Response.Write "Could not send quote details to head office."
End If
%>

<P><A HREF="finance_useasp.htm">Continue</A>
</BODY>
</HTML>

The Resulting Page And Message

Here's the result of our ASP code, as seen in the browser. The confirmation message is a little misleading because it really only indicates that the queue was opened successfully. An error in the Send process wouldn't be detected because of the On Error Resume Next statement—one reason why we referred to this technique earlier as 'quick and dirty':

To confirm that the message was sent, we can view it in MQ Explorer:

Right-clicking the message and selecting Properties shows details about the message. In the Body tab of this dialog, we can view the first 256 bytes of the message body:

Receiving And Reading the Message

We know that our message was delivered to the destination queue OK, because we've seen it in MQ Explorer. However our application will usually want to do something with the messages, and so we need to be able to receive and read them using code. We've produced a simple program in Visual Basic that will read our message on the destination machine.

Creating The Simple Message Reader

To work with MSMQ in Visual Basic (and other languages) it's easier if we provide the programming environment with a reference to the MSMQ type library. In the Project | References dialog, we can select the Microsoft Message Queue Object Library. This will allow us to use the MSMQ named constants in our code, view the MSMQ objects in Object Browser, and get pop-up tips as we type in our code:

The application itself is a simple single form, compiled into a standard EXE project. The form itself contains a couple of labels that will display the values of the message's Label and Body properties, a button to close the program down, and a Timer control:

And because we have a reference to the MSMQ type library, VB knows about the objects that are available as we type the code into the form's Code window:

The Message Reader Code

The Visual Basic code itself is simple. There's a subroutine to close the application down when we click the Close button:

Private Sub cmdClose_Click()
   End
End Sub

All the rest of the work is done in the Timer event of the timer control on the form. We've set the Interval property to 5000 in the timer's Properties dialog so that it occurs every five seconds. The code that runs each time the timer fires first creates a MSMQQueueInfo object and points it at the FinanceQueue queue on the local machine. Remember, this application is running at head office, and we created the queue there in our ASP page:

Private Sub timMsgRead_Timer()
   On Error GoTo timMsgRead_Error
   Dim objQueueInfo As New MSMQQueueInfo
   objQueueInfo.PathName = ".\FinanceQueue"
   ...

Then it creates a MSMQQueue object to refer to the queue with, and opens the queue. Next it creates a MSMQMessage object to hold the received message. Finally, it retrieves the topmost message by calling the queue object's Receive method, displays the values of the Label and Body properties in the label controls on the form, and closes the queue again:

   ...
   Dim objQueue As MSMQQueue
   Set objQueue = objQueueInfo.Open(MQ_RECEIVE_ACCESS, MQ_DENY_NONE)
   If objQueue.IsOpen Then
      Dim objMessage As New MSMQMessage
      Set objMessage = objQueue.Receive(ReceiveTimeout:=1000)
      lblMsgLabel = objMessage.Label
      lblMsgBody = objMessage.Body
      objQueue.Close
   End If
   Exit Sub
timMsgRead_Error:
   lblMsgLabel = "Error reading message"
   lblMsgBody = ""
   Exit Sub
End Sub

And here's the result. It would be easy enough now to write the value of the message's Body property to either a text file or a local database:

© 1998 by Wrox Press. All rights reserved.