Asynchronous Processing


As you know, in your average mainframe batch application, the asynchronous pro cessing model is almost nonexistent. It is not until you incorporate tools such as MQSeries that your existing mainframe batch application models are extended beyond their common linear, sequential processing design. Other than that, your previous mainframe CICS experience using the CICS START/RECEIVE commands certainly qualifies as exposure to asynchronous processing.

Tip  

By identifying any mainframe similarities and using analogies where possible, I am attempting to increase the chance of your transferable knowledge surfacing .

Generally speaking, the following three scenarios are common when you talk about asynchronous processing:

  • A nonblocking call being made from a client-type application to a server- type application

  • A nonblocking call processing at some nondeterminate time and disconnected from the ongoing operational capability of the client-type application

  • A nonblocking call (in some cases) providing a response to the original client-type application

When you develop with .NET, asynchronous processing includes the imple mentation and use of the System.IAsyncResult interface. You will grow to know this interface as basically representing the status of an asynchronous request (i.e., a nonblocking call). A few base classes and properties are associated with the IAsyncResult interface. You will often see one or more of these IAsyncResult members whenever an application is designed to use the asynchronous pro cessing model.

Specifically, AsyncResult and WebClientAsyncResult are the two classes that natively implement the IAsyncResult interface. The four public properties exposed by the IAsyncResult interface are simply AsyncState , AsyncWaitHandle , CompletedSynchronously , and IsCompleted . Other than that, there is one delegate, AsyncCallback . You use this delegate when you want to "call back" a client's method after the asynchronously processed request (nonblocking call) completes .

Note  

If you take a closer quick look at the AsyncResult class, you will notice that it comes from the System.Runtime.Remoting.Messaging namespace. This alone provides an indication of the close interrelationships among such .NET technologies as Remoting, messaging, and asynchronous processing.

Let's move now to a practical example to demonstrate the use of asynchronous processing in a .NET application.

Using MSMQ for Asynchronous Processing

The topic of asynchronous processing can easily be explained and demonstrated without the use of MSMQ. At the same time, it is good to know that the MSMQ tool provides wonderful support for asynchronous processing. Given that, I will leverage your knowledge about MSMQ to help demonstrate the use of asyn chronous processing in a .NET application. Later, I will introduce you to a several other areas where the .NET Framework supports asynchronous processing.

This MSMQ/asynchronous processing demonstration will use the Windows Application VS .NET project template. You will exercise both your COBOL .NET and VB .NET skills. [8] As shown in Figure 20-15, you will implement a simple yet extendable asynchronous processing scenario.

click to expand
Figure 20-15: The application flow of the MSMQ/asynchronous processing demonstration

Before you get into the code-centric portion of the demonstration, you will need to perform several setup tasks . Please note the following prerequisite tasks:

  1. Create a folder at C:\MSMQ-ASYNC-DEMO (optional).

  2. Create two .NET Windows sample projects. Name these new .NET Windows projects MyMSMQAsyncAndTriggerCOBOL and MyMSMQAsyncAndTriggerVB.

  3. Copy both application executables (.exe) and place them inside the C:\MSMQ-ASYNC-DEMO folder for organizational purposes (optional).

  4. Launch the Computer Management console tool by clicking the Start button and selecting Programs Administrative Tools Computer Management. Optionally, you can simply right-click your My Computer icon and choose Manage.

  5. Use the Services MMC snap-in to verify that both the Message Queuing service and Message Queuing Triggers service show a status of "started." You can access the Services MMC snap-in via the Computer Management console.

  6. Create two MSMQ private queues. You can use the same procedure you learned earlier in the chapter to create the two queues. Optionally, use the Computer Management console to access the MSMQ snap-in. I chose to name the two new MSMQ Queues MyFirstTriggerQueue and MyFirstAsyncQueue. The queues were left as not transactional. [9]

  7. Create an MSMQ rule and trigger. [10] You will walk through this task later in the section "Creating an MSMQ Trigger."

With the exception of the MSMQ trigger, you should feel relatively com fortable accomplishing each prerequisite task in the preceding list. If not, please consider reviewing earlier portions of this chapter, earlier chapters, and the sup plementary help sources (MSDN, VS .NET Help, and so forth). Let's turn now to the sample applications.

Tip  

When you use the VS .NET IDE's Server Explorer drag-and-drop feature, consider changing the default MSMQ Queue Path value ( machineName/Private$/QueueName ) to a generic setting by replacing machineName with a period (.). The intended end result would be ./Private$/QueueName . Use the Design view property pages to view and edit the MSMQ queue path. I previously mentioned this in the section "Revisiting Microsoft Message Queuing (MSMQ)." I used the generic setting to enable the sample application's capability to function properly on multiple machines.

The Sample Applications

As you can see in Figures 20-16 and 20-17, the two new MSMQ queues are being used in both sample projects. You will notice that each sample project presents a Windows Form along with a minimal use of Button and Label controls.

click to expand
Figure 20-16: The GUI/Design view of the MyMSMQAsyncAndTriggerCOBOL sample project
click to expand
Figure 20-17: The GUI/Design view of the MyMSMQAsyncAndTriggerVB sample project

When you develop a .NET application that will use MSMQ's asynchronous processing support, you will use the System.IAsyncResult interface through either of the following System.Messaging.MessageQueue class method combinations:

  • MessageQueue.BeginReceive and MessageQueue.EndReceive

  • MessageQueue.BeginPeek and MessageQueue.EndPeek

In the first MSMQ demonstration (in the MyMSMQExampleVB sample appli cation), you saw the use of the MessageQueue.Receive and MessageQueue.Peek methods . Notice the absence of the word "Begin" in the method names that you used earlier.

In the earlier MyMSMQExampleVB example, you were not initiating an asyn chronous processing model. Particularly, the MessageQueue.Receive method easily demonstrates an example of a potentially "blocking" call. If you had coded to allow the sample code to execute the MessageQueue.Receive method when the targeted MSMQ queue was empty, the application would have just "waited" until a message was placed in the queue.

Tip  

Consider experimenting with the previous MyMSMQExampleVB sample code by temporarily commenting out the line that uses MessageQueue1.Peek. This Peek method was actually serving the purpose of getting around the possibility that the queue may have been empty. When the queue was empty, the Peek method simply raised an exception. Observe the use of the Try/Catch logic. The exception was handled by displaying a message box.

Yes, on the surface this might appear to mimic an asynchronous processing model. However, the problem is that the "waiting" application (the client) would not have been allowed to continue processing. Processing would have just "waited" at the point the MessageQueue.Receive method was executed. This type of "client blocked while waiting" scenario is in contradiction to the basic asyn chronous processing model.

Now you'll take a quick peek at the code that was used in each sample project. You'll start with the COBOL .NET portion of the demonstration (see Listing 20-3). Notice that I've included only the most relevant portion of the MyMSMQAsyncAndTriggerCOBOL sample project. In this case, that is the event/method logic for the two Windows Button controls.

Listing 20-3: Code Snippet from the MyMSMQAsyncAndTriggerCOBOL Sample Project
start example
 000010 IDENTIFICATION DIVISION. 000020 CLASS-ID. Form1 AS "MyMSMQAsyncAndTriggerCOBOL.Form1" 000030    INHERITS CLASS-FORM. 000040 ENVIRONMENT DIVISION. 000050 CONFIGURATION SECTION. 000060 SPECIAL-NAMES. 000070    CUSTOM-ATTRIBUTE STA-THREAD CLASS CLASS-STA-THREAD 000080    . 000090 REPOSITORY. . . . 017680 METHOD-ID. button1_Click PRIVATE. 017690 DATA DIVISION. 017700 WORKING-STORAGE SECTION. 017710 01 MyGUIDString PIC X(50). 017720 01 MyMsgString PIC X(25). 017730 LINKAGE SECTION. 017740 01 sender OBJECT REFERENCE CLASS-OBJECT. 017750 01 e OBJECT REFERENCE CLASS-EVENTARGS. 017760 PROCEDURE DIVISION USING BY VALUE sender e. 017770  017780               MOVE "TRIGGER" TO MyMsgString 017790    SET myGUID TO CLASS-GUID::"NewGuid"() 017800    SET MyGUIDString TO myGUID::"ToString"() 017810    INVOKE messageQueue1 "Send"  017820    USING BY VALUE MyMsgString, MyGUIDString 017830    SET PROP-TEXT OF label1 TO MyGUIDString 017840 017850 END METHOD button1_Click. 017860  017870 METHOD-ID. button2_Click PRIVATE. 017880 DATA DIVISION. 017890 WORKING-STORAGE SECTION. 017900 01 MyGUIDString PIC X(50). 017910 01 MyMsgString PIC X(25). 017920 LINKAGE SECTION. 017930 01 sender OBJECT REFERENCE CLASS-OBJECT. 017940 01 e OBJECT REFERENCE CLASS-EVENTARGS. 017950 PROCEDURE DIVISION USING BY VALUE sender e. 017960  017970               MOVE "ASYNC" TO MyMsgString 017980    SET myGUID TO CLASS-GUID::"NewGuid"() 017990    SET MyGUIDString TO myGUID::"ToString"() 018000    INVOKE messageQueue2 "Send"  018010    USING BY VALUE MyMsgString, MyGUIDString 018020    SET PROP-TEXT OF label2 TO MyGUIDString  018030 018040 END METHOD button2_Click. 018050 018060 END OBJECT. 018070 END CLASS Form1. 
end example
 

Please take a moment to review Listing 20-3. For this demonstration, I chose to send String objects to the respective MSMQ private queues. Recall that the String class is serializable (as is the ADO.NET Dataset used in the previous MSMQ demonstration).

Next , take a look at the code used in the VB.NET sample project MyMSMQAsyncAndTriggerVB (see Listing 20-4) . You will need to expand the code region noted as "Windows Form Designer generated code". Notice that the demonstration code is placed after the InitializeComponent() call.

Listing 20-4: Code Snippet from MyMSMQAsyncAndTriggerVB
start example
 Public Class Form1  Inherits System.Windows.Forms.Form #Region " Windows Form Designer generated code "     Public Sub New()       MyBase.New()       'This call is required by the Windows Form Designer.       InitializeComponent()          'Add any initialization after the InitializeComponent() call          Call MyMSMQReceive()     End Sub        Private Sub MyMSMQReceive()       Dim myStringMsg As String       Dim myMessage As System.Messaging.Message       Try             MessageQueue1.Peek(New TimeSpan(0))             myMessage = MessageQueue1.Receive             myMessage.Formatter = New _           System.Messaging.XmlMessageFormatter(New Type() {GetType(String)})             MyStringMsg = CType(myMessage.Body, String)             '****************************************************             Label2.Text = myMessage.Label       Catch myexception As System.Messaging.MessageQueueException          If myexception.MessageQueueErrorCode = _             System.Messaging.MessageQueueErrorCode.IOTimeout Then               Label2.Text = "The MSMQ needs to be loaded first"             End If       End Try           ' Add an event handler       AddHandler MessageQueue2.ReceiveCompleted, _       AddressOf MyMSMQBeginReceive       ' Begin the asynchronous receive       MessageQueue2.BeginReceive()     End Sub         Public Shared Sub MyMSMQBeginReceive(ByVal source As Object, _     ByVal asyncResult As System.Messaging.ReceiveCompletedEventArgs)          'Connect to the MSMQ queue.          Dim myqueue As System.Messaging.MessageQueue = _          CType(source, System.Messaging.MessageQueue)              'End the asynchronous BeginReceive          Dim myMessage As System.Messaging.Message = _          myqueue.EndReceive(asyncResult.AsyncResult)              'Example code to exit application          'Application.Exit()          MsgBox("Message received: " & myMessage.Label)          myqueue.BeginReceive()              ''Example code to Load MSMQ Private Queue          'Dim mymsg As String = "ASYNC"          'MessageQueue1.Send(mymsg, "ASYNC")     End Sub . . . Private Sub Button1_Click(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles Button1.Click          'exit application          Application.Exit()       End Sub End Class 
end example
 

In Listing 20-4, the expected logic to receive the MSMQ String type message has been included. The logic shown for the MyMSMQBeginReceive subprocedure actually implements the asynchronous processing. In other words, the two lines of coding in Listing 20-5 are almost all that you need.

Listing 20-5: Code Snippet from MyMSMQAsyncAndTriggerVB Highlighting the Code Needed to Initiate Asynchronous Processing
start example
 . . .          ' Add an event handler          AddHandler MessageQueue2.ReceiveCompleted, _          AddressOf MyMSMQBeginReceive          ' Begin the asynchronous receive          MessageQueue2.BeginReceive() . . . 
end example
 

As you can see, these two lines of code accomplish the task of adding an event handler to the MyMSMQBeginReceive subprocedure. The targeted event is the ReceiveCompleted method being raised from MessageQueue2 . The second line of code shown simply starts the asynchronous process with the BeginReceive method. While this MyMSMQAsyncAndTriggerVB sample application continues to execute, the BeginReceive method will be there, listening/running in the back ground and waiting for a message to be received into the specified MSMQ private queue.

Note  

When you execute the BeginReceive function without a parameter (as I did), you are requesting that the asynchronous process wait for an MSMQ message indefinitely. Alternatively, you can specify a timeout parameter using the System.TimeSpan format.

The logic shown inside the MyMSMQBeginReceive subprocedure ends the asynchronous receive by receiving the MSMQ message. Notice the BeginReceive method being used again to resume the asynchronous receive process. In a real- life application, you would typically "do something" with the received message. For demonstration purposes, a message box will be used to simply provide visual notification that the message has been received.

Before you move on to the topic of MSMQ trigger setup, this is a good time to do a bit of preliminary testing. During a development life cycle, this phase of testing could be referred to as unit testing.

A Preliminary Test

Let's do a quick test. Execute the MyMSMQAsyncAndTriggerCOBOL sample appli cation. Proceed to click each of the two buttons a few times. Observe that the GUI displays the GUID on each Label control (see Figure 20-18).

click to expand
Figure 20-18: The MyMSMQAsyncAndTriggerCOBOL sample application reflects the GUID of each message sent to the MSMQ private queues.

Next, use the Computer Management console to view the status of your two MSMQ private queues. As shown in Figure 20-19, several messages have accumu lated that indicate a successful preliminary test. You will notice (in Figure 20-19) the step of manually purging the queues (right-click the Queue Messages folder and select All Tasks Purge). Each private queue should be manually purged after the preliminary test is complete.

click to expand
Figure 20-19: Using the Computer Management console to view the MSMQ private queues and to manually purge the accumulated messages

Finally, manually execute the MyMSMQAsyncAndTriggerVB sample project. Assuming the MSMQ private queues are empty, you should see that the Windows Form GUI display from the Label control reflects that fact. Next, simply test the one Button control to manually exit the application.

Do not discount the significance of testing this single Button control that simply executes one code instruction:

 Application.Exit() 

I need to point out that this little Button control feature demonstrates the sig nificant value gained from the asynchronous processing model. This Button control actually works. What's the big deal, right? Think about it. You can use this Button control to interact with your application while the BeginReceive asyn chronous process is running in the background. In other words, the BeginReceive call is not blocking the execution of the Button1_Click event method.

Establishing a nonblocking call while the client application is allowed to con tinue processing is one of the most significant aspects of the asynchronous processing model.

Your last unit test will be to follow this simple test script:

  1. Execute the MyMSMQAsyncAndTriggerCOBOL sample application . Use the appropriate button control to place just one message into the MyFirstTriggerQueue MSMQ queue.

  2. Manually execute the MyMSMQAsyncAndTriggerVB application . This time, the Label control should reflect that the MSMQ message was received. The GUID value being displayed provides an easy way to match one-to-one the sent message to the received message (see Figure 20-20).

    click to expand
    Figure 20-20: A side-by-side display of each sample application and the resulting message box during one phase of the preliminary unit testing

  3. Use the appropriate Button control on the sample application MyMSMQAsyncAndTriggerCOBOL to place just one message into the MyFirstAsyncQueue . You should notice that the MyMSMQAsyncAndTriggerVB sample application automatically displays a message box. The message box should reflect the appropriate GUID value.

    Tip  

    During your preliminary testing, you might even place a few breakpoints in the VS .NET IDE code view window. This will give you the opportunity to step through your code and interactively debug if needed.

This completes your preliminary unit testing. Close each VS .NET IDE window. To simplify this demonstration a bit, copy both sample executables (.exe) to one common folder, C:\MSMQ-ASYNC-DEMO (see Figure 20-21). You will return to these executables in the next section.

click to expand
Figure 20-21: Place the sample executables in the C: \MSMQ-ASYNC-DEMO to simplify the demonstration path displays.

In the next section you will walk through the creation of an MSMQ rule and trigger.

Creating an MSMQ Rule and Trigger

After you launch the Computer Management console and navigate to the Message Queuing node, you will notice a Message Queuing Triggers node (see Figure 20-22). You will start here. Notice that the Computer Management console window exposes the existence of the Outgoing Queues node (directly underneath the main Message Queuing node). It is good to be aware of this. If for any reason connectivity to your private or public queue is unavailable, your MSMQ messages will accumulate in the Outgoing Queues until such time that connectivity is reestablished.

click to expand
Figure 20-22: The Message Queuing Triggers node as shown in the Computer Management Console window
Note  

You will need administrative-level security on your local workstation to use the MSMQ trigger feature. Normally, for a development machine, this requirement is acceptable and granted.

Follow these steps to create an MSMQ rule:

  1. Right-click the Rules node and select New Rule (see Figure 20-23). A series of prompts will follow.

    click to expand
    Figure 20-23: Preparing to create a new MSMQ rule

  2. Enter a name and description in the New Rule window. You can use any name that you feel to be appropriate (see Figure 20-24). Click Next.

    click to expand
    Figure 20-24: Naming and describing the new MSMQ rule

  3. Add one or more conditions. Using the drop-down list, choose and add as appropriate. As shown in Figure 20-25, I have added just one condition. Click Next.

    click to expand
    Figure 20-25: Adding conditions for your MSMQ rule

  4. Next, you can choose to trigger a COM component or a stand-alone executable. Select the "Invoke standalone executable (EXE)" radio button and enter the appropriate executable path (as shown in Figure 20-26). Be sure to select the "Interact with desktop" check box. Click Finish.

    click to expand
    Figure 20-26: Specifying the standalone executable choice. Also, the "Interact with desktop" option is checked.

    Note  

    The "COM component invocation" choice available for MSMQ triggers would have applied to the use of a class library (.dll) file. This was the type of project file that you learned about in Chapter 19.

That completes the creation of an MSMQ rule. Congratulations!

Next, you need to create an MSMQ trigger to use the MSMQ rule you just created. To initiate the short series of MSMQ trigger creation prompts, you can use the same Message Queuing Triggers node area you used to create the MSMQ rule. Optionally, you can navigate upward and use the Triggers node area located underneath the Private Queues node (see Figure 20-27).

click to expand
Figure 20-27: Preparing to initiate the MSMQ trigger creation prompts

I found that using the Triggers node underneath the Private Queues node (MyFirstTriggerQueue) worked well. If you choose this route, you are spared the need to enter the queue path name information. Personally, I prefer not having to enter the queue path name information. It's up to you. I'm choosing to use the Triggers node underneath the Private Queues node. Start the series of MSMQ trigger creation prompts by right-clicking the Triggers node. Then select New Trigger and follow the short series of prompts.

  1. The first prompt asks you to enter the name of the MSMQ trigger. As shown in Figure 20-28, I have entered an appropriate name. I chose to change the message processing type from Peeking to Retrieval. This will cause the MSMQ message to be removed from the queue. I left the remaining settings at their default values. Notice that the "Queue path name" field is already filled in. Click Next.

    click to expand
    Figure 20-28: Entering the name for the new MSMQ trigger

  2. The last prompt gives you the chance to attach your trigger to any existing MSMQ rules. Proceed to attach the one rule that is shown (see Figure 20-29). Click Finish. That is it!

    click to expand
    Figure 20-29: Attaching the MSMQ rule to the MSMQ trigger

    Tip  

    During my development and testing, I needed to use the Services MMC snap-in to stop and restart the Message Queuing Triggers service a few times (the Services MMC snap-in is exposed in the Computer Management console). Of course, this came after editing the properties of my existing triggers and rules. You may or may not have the same experience. As an afterthought, I decided to adopt a practice of stopping the Message Queuing Triggers service before I edited existing triggers. Then I started the Message Queuing Triggers service after I was done. This seemed to work better. Additionally, I found it helpful to detach and reattach my rules a few times while tweaking the conditions.

You can now conduct your full integration testing by following these few steps:

  1. Navigate to the folder location C:\MSMQ-ASYNC-DEMO and execute MyMSMQAsyncAndTriggerCOBOL.exe by double-clicking the .exe file.

  2. When you click the first button to send an MSMQ message to the MyFirstTriggerQueue private queue, the MyMSMQAsyncAndTriggerVB sample application should automatically launch. Keep in mind that as the MyMSMQAsyncAndTriggerVB application launches, an asynchronous "request cycle" has begun .

  3. Send an MSMQ message to the MyFirstAsyncQueue private queue. The MyMSMQAsyncAndTriggerVB application should automatically display a message box when an MSMQ message is sent to the MyFirstAsyncQueue private queue. The asynchronous process is resumed after the message box is displayed.

That concludes this chapter's demonstration with MSMQ and asynchronous processing. The MSMQ product has many other features that you can explore. The .NET Framework has many other classes to assist your use of the MSMQ product. You can further explore the use of asynchronous processing as well. As your needs dictate , please consider taking advantage of the references provided at the end of this chapter in the "To Learn More" section.

start sidebar
Other .NET Support for Asynchronous Processing

The .NET Framework exposes support for asynchronous processing in several areas (in addition to MSMQ). In any case, the basic model/approach will look familiar to you. You will recognize that the BeginXXX and EndXXX methods (methods beginning with the "Begin" and "End" prefixes) are available. Consider the following opportunities for introducing asynchronous processing into your application design:

  • When you do file I/O, you will notice that there are FileStream.BeginRead and FileStream.BeginWrite methods available.

  • When you do stream I/O, the Stream.BeginRead and Stream.BeginWrite methods work well for controlling an asynchronous cycle.

  • When you do socket I/O, the Socket.BeginReceive method may be useful

  • When you do networking/HTTP logic, look for HttpSimpleClientProtocol.BeginInvoke .

  • When you work with ASP.NET XML Web services, System.Web.Services.Protocols.WebClientAsyncResult will come in handy.

  • When you work with ASP.NET Web Forms, look for the following application-level method: HttpApplication.AddOnBeginRequestAsync .

  • When you work with .NET Remoting channels (HTTP and TCP) and prox-ies, consider using the RemoteAsyncDelegate.BeginInvoke method.

end sidebar
 

You'll now turn your attention to an alternative .NET offering for distributed processing.

[8] Isn't being bilingual fun?

[9] Although you won't make use of this feature during this demonstration, you certainly should make a mental note of the availability of this transactional feature. If your application design recognizes a logical unit of work surrounding the sending and receiving of MSMQ messages to/from one or more queues, the MSMQ transactional feature can offer great value.

[10] The use of an MSMQ rule and trigger is not necessarily needed to implement an asynchronous processing model. I just wanted to show you another MSMQ feature that you can leverage.




COBOL and Visual Basic on .NET
COBOL and Visual Basic on .NET: A Guide for the Reformed Mainframe Programmer
ISBN: 1590590481
EAN: 2147483647
Year: 2003
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net