Review the sample client application code to learn how you can understand the differences between a synchronous client and an asynchronous client.
%SOAM_HOME%\4.1\samples\DotNet\CS\SampleApp\sampleApplication.NET.2003.sln
%SOAM_HOME%\4.1\samples\DotNet\CS\SampleApp\sampleApplication.NET.2005.sln
%SOAM_HOME%\4.1\samples\DotNet\CS\SampleApp\sampleApplication.NET64.2005.sln
%SOAM_HOME%\4.1\samples\DotNet\CS\SampleApp\AsyncClient\AsyncClient.cs
%SOAM_HOME%\4.1\samples\DotNet\CS\SampleApp\Common\MyMessage.cs
The service required to compute the input data along with additional application parameters are defined in the application profile:
%SOAM_HOME%\4.1\samples\DotNet\CS\SampleApp\SampleAppDotNetCS.xml
The client application sample sends 10 input messages with the data "Hello Grid !!" and retrieves the results.
Results are returned asynchronously with a callback interface provided by the client to the API. Methods on this interface are called from threads within the API when certain events occur. In the sample, the events are:
An asynchronous client is very similar to a synchronous client. The only differences are:
As in the synchronous client tutorial, initialize the client and implement the MyMessage class to handle the input/output data; refer to Your First Synchronous Symphony C# Client and Service, specifically:
With an asynchronous client, when a task is completed by the service, there must be a means of communicating this status back to the client. The response handler is implemented for this purpose. It is called by the middleware each time a service completes a task.
In this sample, the AsyncClientOnResponse() method is the response handler. The method accepts the TaskOutputHandle as an input argument, which is passed to the method by the middleware whenever the respective task has completed.
Extract the message from the task result using the GetTaskOutput() method. Display the task ID, internal ID (taskCount), and output message.
Increment the m_numReceivedTasks variable. Use the lock keyword to ensure that another thread does not try to increment the variable while it is being accessed.
The m_eventOccured.Set() method releases the waiting main execution thread of the client.
The exception handler method is called by the API when an exception of type SoamException occurs within the scope of a session.
Print out the exception message and set the Boolean error flag (m_noErrorReported) to false. Use the lock keyword to ensure that another thread does not try to set the flag while it is being accessed.
To send data to be calculated in the form of input messages, you connect to an application; refer to Step 3: Connect to an application of the synchronous client tutorial.
A session is a way of logically grouping tasks that are sent to a service for execution. The tasks are sent and received asynchronously.
When creating a session, you need to specify the session attributes by using the SessionCreationAttributes object. In this sample, we create a SessionCreationAttributes object called attributes and set four parameters in the object.
In this example, we set the following parameters:
The first parameter is the session description. This is optional. The session description can be any descriptive name you want to assign to your session. It is for information purposes, such as in the command-line interface.
The second parameter is the session type. The session type is optional. You can leave this parameter blank and system default values are used for your session.
The third parameter is the session flag. When creating an asynchronous session, set the flag to SessionFlags.ReceiveAsync. This flag indicates to Symphony that this is an asynchronous session.
Associate the event handler method (AsyncClientOnResponse) with the OnResponse event; refer to Step 2: Implement the response handler method to retrieve output messages. This is necessary so that the OnResponse event knows which method to execute when the event is triggered. The method is called by the API whenever a task response is ready. Similarly, associate the AsyncClientOnException() method with the OnException event to handle exceptions of type SoamException if they occur. This method is called by the API when an exception occurs within the scope of the session; refer to Step 3: Implement the exception handler method (callback).
In this step, we create 10 input messages to be processed by the service. We call the MyMessage constructor and pass three input parameters: ID (taskCount), the Boolean value (false) to indicate asynchronous communication, and a message string ("Hello Grid !!"). When a message is sent, a task input handle is returned. This task input handle contains the ID for the task that was created for this input message.
After all 10 tasks (messages) have been sent to the service, the main client execution thread must wait for all tasks to be processed before closing the session. As each task is completed by the service, the m_numReceivedTasks variable is incremented; refer to Step 2: Implement the response handler method to retrieve output messages. The WaitForComplete() method is used to suspend the main client execution thread until all messages are received. The method contains a loop that checks if the number of replies equals the total number of tasks sent; if they are not equal, the thread blocks by calling m_eventOccured.WaitOne() until it is signalled to resume execution. The thread is released by calling m_eventOccured.Set() each time a task is completed or if an exception occurs. When all the replies have been received, close the session.
As is the case with the connection object, the creation and usage of the session object, i.e., sending and receiving data, must be scoped in a try-finally block. The finally block, with the session.Close() method, ensures that the session is always closed whether exceptional behavior occurs or not. Failure to close the session causes the session to continue to occupy middleware resources.