As we know, the modern world's enterprise applications are more dynamic and require more complex communication among processes as well as among different application components. This is where MSMQ (Microsoft Message Queue) comes in the picture. MSMQ is essentially an application that guarantees sending and receiving messages reliably in a disconnected distributed environment. But the real power of MSMQ provided with MSMQ Triggers. Though creating Triggers manually is a fairly easy task, creating it dynamically at runtime and firing it to take some custom action is a more complex task. Recently I was implementing such a complex task in my project and believe me, at one stage when my clock was ticking past 3 A.M. I was wondering why did I choose this IT field which causes me such miserable moments in life ... Anyway, by a Click and Go approach I finally got the job done.
Basically MSMQ is standardized messaging (data transferring) technique in an enterprise environment. Data is transferred in a serializable format as a message to the queue. At the other side it's deserialized to get real data. An MSMQ message can be anything from a simple string to any class object or from an XML file to PDF Documents. Fortunately, now MS VS.NET 2005 provides support for MSMQ 3.0. To implement MSMQ in your .NET application you have to import the
System.Messaging Namespace, which can be imported by adding reference to the
System.Messaging assembly. Anyway, to keep track of this article I won't go in much detail about MSMQ, newbies can find lot of online tutorials about MSMQ including MSDN.
About MSMQ Trigger
At a basic level you can think of the MSMQ Trigger as like any simple database trigger. They are very handy when we need to take custom action in response to the arrival of incoming message(s) to the particular message queue. MSMQ Triggers allows us to take one of two actions, either you can execute a standalone .exe file or you can Invoke a COM+ service component's method. This way you can consume your COM+ services in the .NET world. So without further discussion about its advantages let me show you both of these approaches here. But before we go to develop a code let's see the other side of Trigger because it does have other sides as well.
About Trigger Rule
Surely, rule can be defined as the other side of the MSMQ Trigger. Rule consists of two components: Condition and Action. Conditions are checked against the properties of incoming message(s) which are evaluated to true or false. A single rule can contain more than one condition like the message body contains specific words, message labels do not contain specific words, message priorities and so on. Action is an execution of real business logic. When conditions of rule evaluates to true action associated with rule, will be taken. As I mentioned before, action can be taken by executing standalone .exe file or it can invoke COM+ service component method passing its required parameters. In order to fire Trigger successfully you must associate rule(s) with Trigger. What I mean is that there must be rule that exists to associate with Trigger. So let's move to the details of creating triggers and rules programatically to execute needed action.
To create an MSMQ Trigger in your .NET application you must have it installed in your machine. If you are using MSMQ 3.0 then you dont have to install it separately but if you need to install it then you can download it from Microsoft download center. Moreover, when you decide to work with MSMQ Triggers you just need to make sure that your Message Queuing Triggers service is running. This service is required to fire MSMQ Triggers. I have it up and running in my machine as shown in the figure below:
To deal with Triggers in a programatic way you have to Import the MSMQ Trigger Objects library. To import this library in your application you need to add a reference to the mqtrig.dll file which resides under the %System Root%\Windows\System32 directory. When you finish adding reference to the mqtrig.dll file you can see that you have new references to the assembly
MSMQTriggerObjects which will be added to your project as illustrated in below figure:
For MSMQ Tigger to work you must have a reference to the monitoring Message Queue which you need to fire a trigger on. So let's first write code to get a reference to a message queue:
Dim strQueuePath As String = ".\private$\TestQueue"
Dim QMsgQue As MessageQueue
If MessageQueue.Exists(strQueuePath) Then
QMsgQue = New MessageQueue(strQueuePath)
QMsgQue = MessageQueue.Create(strQueuePath)
The above code will create a Message Queue named
TestQueue on MSMQ Server (if it does not exist there) and give a reference to queue in your application to work with.
The first task is to create a rule to specify conditions and actions of a trigger. Once we have rule available then we can associate this rule with trigger so we can decide to fire a trigger action or not based on an evaluation of condition. We need to specify the condition and action for rule, though, you can leave the condition part unspecified if you don't want to check any condition. Leaving the condition part blank will always evaluate condition as true. Of course, there are two options provided for action part:
- Executing stand alone EXE file and
- Invoking method of COM+ service component
So let's write code for our first option, executing a standalone EXE file:
Dim RuleBuilder As New System.Text.StringBuilder
RuleBuilder.Append("EXE" & vbTab)
RuleBuilder.Append("C:\ASP.NET\CreateDir\CreateDir\bin\Debug\CreateDir.exe" & vbTab)
Dim allAction As String = RuleBuilder.ToString
Dim ruleID As String = String.Empty
Dim objRule As New MSMQTriggerObjects.MSMQRuleSet
objRule.Add("MyTestRule", "Test Rule",String.Empty, _
allAction,"MSMQTriggerObjects.MSMQRuleHandler", 0, ruleID)
Dim strCondition As String = "$MSG_LABEL_CONTAINS=Test"
Creating rule this way seems really simple but there are some points to keep in mind. First, make sure that path of .exe file is correct and file does exist at a given path otherwise an exception will be thrown at runtime. Second, you must first Initialize the
MSMQRuleSet object by calling its
Init() method passing it name of machine where rule is to be created. The
Add() method of
MSMQRuleSet object is used to add rule to the MSMQ server. The parameter passed to the
Add() method are name, description, condition (note that leaving the condition blank means its true in all case), action (EXE Invocation), implementation of rule, flag (indicates whether excuting an EXE file should interact with deskop or should run silently). Lastly,
ruleId is a reference parameter respectively. Upon successful creation of rule this
ruleId will be assigned GUID. This
ruleId is useful when you want to refer to a rule by its Id or if say, you want to delete a rule.
Our second option which is Invoking a method of the COM+ service component is not as simple as our first option because it interacts with an unmanaged code which is not under control of CLR. Additionally, for this option to work you must have a service component available and be registered with component services in your machine. If you are new to creating and registering a service component then I suggest you check for it across the web and I am sure you will find lot of tutorials and articles on it. You can check for registered service components in your machine under Control Panel --> Administrative Tools --> Component Services. You can even access it from the Run command menu by typing in dcomcnfg command and pressing Enter. The below figure shows the component which I am going to use to invoke its method.
To implement the COM+ service component invocation in your application you just need to change an action part of rule definition and the rest will be the same.
RuleBuilder.Append("COM" & vbTab)
RuleBuilder.Append("COMAndMSMQTrigger.TraceMSMQMessage" & vbTab)
RuleBuilder.Append("HelloUser" & vbTab)
RuleBuilder.Append("$MSG_LABEL" & vbTab)
Dim allAction As String = RuleBuilder.ToString
The only important part in the above code is the parameters you pass to a method of COM component. The parameters you can pass must match the number of parameters a method accepts and order of paramaters in a method signature. You can pass various type of parameters like a message body as string, as class object, message Id and so on.
The next task is to create tigger so that we can associate existing rule with it.Below code will create trigger in your application.
Dim TrgID As String = String.Empty
Dim objTrg As New MSMQTriggerObjects.MSMQTriggerSet
Here again you must first call the
Init() method on TriggerSet object passing it machine name and then you will be able to call any other method on it. Using
AddTrigger() method you can create Trigger. The parameters you pass to this method are again similar to
AddRule() method. Parameters to the
AddTrigger() method are name of trigger, full name of queue, system queue identifier in this case which happens to be
SYSTEM_QUEUE_NONE, flag to enable or disable trigger, flag to create serialized or nonserialized trigger which indicates to process messages in the order they arrive in a monitored queue or process it randomly, message processing type enum and finally
triggerId which will be GUID. You use
AttachRule() method of
TriggerSet object to associate rule with trigger and use
DetachRule() method to deassociate rule from trigger.
So now our final task is to fire a trigger. To do so you need to send a message to a monitored queue and it will cause the message received event to be fired in a queue. The received event of the queue will cause an associated rule to evaluate its condition to be true or false. If it evaluates to true then the trigger will be fired and triggering an action will be taken or else no action will be taken. The below code will send a message to our monitored queue to fire an event in the queue.
Dim Msg As New Message()
Msg.Label = "Test""
'Send message to queue to cause message receive event to occurre
'Close message queue
'You can even delete trigger when it finish job
When a message is received in a queue a triggering service will fire all the triggers associated with the queue depending on the condition specified in the rule associated with the triggers and defined action in the rule(s) will be taken.
Points of Interest
Up until now we have seen that MSMQ Triggers are such powerful objects that they can be used to interact with native .NET applications as well as unmanaged COM objects. They provide a better level of control over the customization process. With MSMQ Triggers you can take a programatic decision about creating, firing and deleting rule(s) and trigger(s). But at the same time don't forget to keep an eye on the red light, I mean care must be taken in exception handling while practicing with MSMQ Triggers because sometimes its hard to figure out the proper reason of thrown exception. It may be possible that any unhandled exception cause your triggering service to be stopped and until you come to know about that and manually restart a service again you might lose some message proccessing as well.
After all when you think about developing multitiered or distributed applications, MSMQ considers one of the richest objects for synchronous and asynchronious message processing for applications and processes communication and of course triggers add a lot more to its value by providing programmatic flexibility.
I hope this article will give you little reason to cheer about using MSMQ Triggers in your projects whenever you need to, and it prevents at least someone's life to become miserable. Please feel free to contact me If you have any query about MSMQ Triggers. I'll try my best to solve your problem.