Flex integration with Microsoft Message Queuing (MSMQ) using WebORB – Part I – Client Side
.NET, Architecture, Flex May 31st, 2008A big problem in my current project is Concurrency. A client loads a Tree in his Flex application and starts making changes to this tree. If another client also makes changes in the Tree, then we have a Concurrency problem. We thought of two approaches of dealing with this problem. One of them is using Messaging with MSMQ. We did however had some issues developing this and are still trying to make it work.
We mainly worked with two examples provided by WebORB to figure things out. One of them is the Flex Messaging and MSMQ example from the WebORBConsole --> Examples --> Real-time Messaging. The other one is the MSMQ to Flex Data Push example from the site of the midnight coders. In the first example Flex is the Producer and Consumer of Messages. In the second example the Server produces Messages and Flex consumes them.
What do you need to run these examples:
- MSMQ: If you look into Computer Management under Services and Applications you should see a folder Message Queuing. If not I suggest you google to find out how to install this onto your computer. For Vista you'll need to go to the Control Panel --> Programs and Features --> Turn windows features on or off. There you should find a checkbox for installing MSMQ.
- WebOrb for .NET --> In your site you only need the weborb.dll, so this installation isn't really needed. But it comes with a lot of documentation and examples, so if you haven't installed it yet, go and do so now!
- The Messaging Server (WebOrb) should be online. If you're using the WebOrb30 installation to run your examples, then the Messaging Server is started by weborbee.exe. In your project website however, you shouldn't use this weborbee.exe. You only need to copy the global.asax. If you look into this global.asax, you'll see the weborbMessagingServer is started there. I'll show in the examples how to make sure the MessaginServer is online.
When you open the Flex Consumer Resource from the second example you'll see in the properties of the Project --> Flex Compiler that a services-config.xml file is compiles with the application. In this file Channels and Destinations are declared. We left this out so we could choose at runtime which Channel and Destination to use.
Ok, let's start with the Flex Client Side. Here's the example somehow adjusted to our means. I'll go through it piece by piece. For now don't bother too much about the server side. I'll go deeper into that later.
-
public function onCreationComplete(event:FlexEvent):void {
-
registerClassAlias("Messaging.Car", Car);
-
pingWeborb();
-
}
-
-
private function pingWeborb():void {
-
var ro:RemoteObject = new RemoteObject("GenericDestination");
-
ro.source = "Weborb.Management.ManagementService";
-
ro.endpoint = "http://{server.name}/indiegroup-edumatic3-prod/weborb.aspx";
-
ro.ping.addEventListener(ResultEvent.RESULT, onPingResult);
-
ro.ping.addEventListener(FaultEvent.FAULT, onPingFault);
-
ro.ping();
-
}
We register an Alias for the Car class so it'll be mapped correctly to the C# Messaging.Car class.
Next we call the function pingWeborb() which will ensure us that the MessagingServer is started before we start to send Messages. By triggering the weborb gateway (weborb.aspx) in your site, you'll be starting the MessagingServer (in Global.asax). If you are not using the weborb30 site, make sure you haven't started the MessagingServer with the Weborbconsole in weborb30 site. If you want to be sure of this, go to Task Manager --> Processes and kill the w3wp.exe process.
The GenericDestination can be found in the remoting-config.xml in the WEB-INF\flex folder along the server side. More on this later. The source is the Class instance that will be created and the endpoint the url of the gateway. Make sure you use the RemoteObject class from the mx.rpc.remoting.mxml package, as this RemoteObject has an endpoint property. There's also a RemoteObject class in the mx.rpc.remoting package which has no endpoint property. Adding two EventListeners and executing the ping() function in the Weborb.Management.ManagementService class instance.
-
private function onPingResult(result:ResultEvent):void {
-
connectAsConsumer("johleroqueue");
-
connectAsProducer("johleroqueue");
-
}
-
-
private function onPingFault(fault:FaultEvent):void {
-
Alert.show( "Server reported an error - " + fault.fault.faultDetail);
-
}
If the Ping was successfull, then onPingResult should be triggered, in which we'll connect as a Consumer and as a Producer. If the Ping was unsuccessfull, onPingFault will be triggerd and an Alert Box will be shown with the error. If something goes wrong here, I would start a http sniffer like Charles to see if the Gateway is called. If it is, start by creating some breakpoints in Flex and certainly in the global.asax on the serverside. Make sure to keep on reading even if things don't work as I will talk about some other problems I've encountered. Maybe that one of these problems will be the issue that's causing your problem.
-
private function connectAsConsumer(subTopic:String):void{
-
var cs:ChannelSet = new ChannelSet();
-
var uri:String = "rtmp://{server.name}:2037/MessagingService";
-
var channel:WeborbMessagingChannel = new WeborbMessagingChannel(subTopic, uri);
-
channel.addEventListener(MessageEvent.MESSAGE, onMessage);
-
cs.addChannel(channel);
-
-
consumer = new WeborbConsumer();
-
consumer.channelSet = cs;
-
consumer.destination = "ExampleDestination";
-
consumer.subqueue = subTopic;
-
consumer.addEventListener(MessageAckEvent.ACKNOWLEDGE, onMessageAck);
-
consumer.addEventListener(MessageFaultEvent.FAULT, onMessageFault);
-
consumer.subscribe();
-
}
Ok, first we connect as a Consumer, because the connectAsProducer function will also be sending a message. First we create a ChannelSet containing a WeborbMessagingChannel. I haven't gone deep into this Channel thing, but one thing that was strange to me was that no site is given in the rtmp uri. Apparently the MessagingServer is listening to a port. The /MessagingService points to a folder in the Applications folder under the root of your site. In this MessagingService folder it's possible to place an app.config where you can change some configurations. The channel triggers a MessageEvent.MESSAGE event when a message is Consumed.
The destination can be found in the messaging-config.xml under WEB-INF\flex. In there you'll find an entry path with the name of the queue. This path together with the subqueue (in my case johleroqueue) will be the name of your queue. If the path is .\private$\WEBORB-[destinationName] and the destination name "ExampleDestination" then a queue weborb-exampledestination-johleroqueue will be created. The first time the queue is used it will automatically be created by weborb. However, if weborb creates the queue, you will not be able to access it with the Computer Management tool. Apparently access is denied. A workaround for this is to manually create this queue before running the example. If you manually create it, you'll have access rights. However, you'll need to give the Network Service rights to the queue, otherwise the messages will not arrive (you can check this!). Weborb will then use the queue you created if you use the same name off course. The ACKNOWLEDGE event listener will let the consumer know if subscription was successfull. The other listeners are clear enough I guess.
-
private function connectAsProducer(subTopic:String):void{
-
var cs:ChannelSet = new ChannelSet();
-
var uri:String = "rtmp://{server.name}:2037/MessagingService";
-
var channel:WeborbMessagingChannel = new WeborbMessagingChannel(subTopic, uri);
-
cs.addChannel(channel);
-
-
producer = new WeborbProducer();
-
producer.channelSet = cs;
-
producer.destination = "ExampleDestination";
-
producer.subqueue = subTopic;
-
producer.addEventListener(MessageAckEvent.ACKNOWLEDGE, onMessageAck);
-
producer.addEventListener(MessageFaultEvent.FAULT, onMessageFault);
-
-
var car:Car = new Car();
-
car.Make = "Zakke";
-
car.Mileage = 10;
-
car.Model = "Makke";
-
producer.send(new AsyncMessage(car));
-
}
Connecting as Producer is quite similar to the Consumer with the exception of the send function. Meanless to say that the Producer and Consumer need to connect to the same queue. Next the Producers sends a Car instance.
-
private function onMessage(event:MessageEvent):void {
-
trace(event.message.body);
-
//Put a breakpoint here
-
//var body:* = event.message.body;
-
}
-
-
private function onMessageAck(event:MessageAckEvent):void {
-
//Put a breakpoint here
-
}
-
-
private function onMessageFault(event:MessageFaultEvent):void {
-
//Put a breakpoint here
-
}
If the Consumer has successfully suscribed, then a onMessageAck should be triggered. If the Producer has successfully connected, then onMessageAck should be triggered a second time. The onMessageAck from the Producer does not mean that the message has successfully been send, it only means that the Producer has been able to connect to the MessagingService. There doesn't seem to be a clear way of knowing if the Message has successfully been send. However, if the Consumer gets the message, then other Consumers will have gotten the message too. After this onMessage should be triggered and a Car (if the server side is configured right) should be delivered.
Adios, Johlero!
Thx to the midnight coders!
June 21st, 2008 at 11:40 pm
Excellent article. Really helped me as I am beginning with MSMQ. The example included with the installation of WebOrb is quite confusing.
Keep writing,
Buzzy
July 18th, 2008 at 8:08 am
connectAsConsumer(“johleroqueue”);
connectAsProducer(“johleroqueue”);
why is consumer there before producer?
What would you expect to see when this is up and running properly?
How do you check the queue?
I had to change the link from “http://{server.name}/indiegroup-edumatic3-prod/weborb.aspx”;
to
“http://{server.name}/weborb30/weborb.aspx”;
in order to get around the server connection error, is that correct due to my installation or this should not happen?
thanks for putting up great information and any feedback would be appreciated.
July 20th, 2008 at 11:07 am
Why is consumer there before producer?
This isn’t necessary but if you would first connect the Producer and send a sort of testmessage, then your consumer wouldn’t get the testmessage. The Consumer receives messages, so it seemed better to connect the Consumer first.
What would you expect to see when this is up and running properly?
I’ll look for a screenshot of what you should see. Basically you should see an application with some buttons (buttons to connect as consumer, connect as producer, send messages, disconnect, …)
How do you check the queue?
Click on start –> right-click Computer –> Manage –> Services and Applications –> Message Queuing –> Private Queues –> There you should see the queues. WebORB adds security however so you will not be able to see the messages that are in the queue. If you do want to see them, you have to create the queue yourself before WebORB does.
I had to change the link from “http://{server.name}/indiegroup-edumatic3-prod/weborb.aspx”;
to
“http://{server.name}/weborb30/weborb.aspx”;
You can use the Weborb30 installation, but I would recommend that you set up a site in IIS besides weborb30 to test the example. Weborb30 uses a weborbee.exe to start the MessagingServer, so they do not depend on settings in your IIS. So using weborb30/weborb.aspx will work, but I would definitely try to set up your own site. Read the PartII for that as the server side is explained there! A lot of answer to your questions will be found there!
If you have more questions, let me know, as it’s hard to explain Messaging in a few lines…
Greetz, Johlero aka Lieven Cardoen
July 21st, 2008 at 7:17 am
Thanks for the reply, I will let you know how I go with part II. Thanks.
September 11th, 2008 at 12:14 am
Awesome write up. Very good information for the MSMQ. I found the pinging of the WebOrb messaging service one of the most helpful scripts I’ve come across for working with RSO and WebOrb.
Many Thanks,
-kevin
November 19th, 2008 at 10:46 pm
Very interesting article, i bookmarked your blog
Best regards
November 20th, 2008 at 8:04 pm
Thx!
December 22nd, 2008 at 2:25 pm
hi,
Excellent article, but i have a problem, the message consumed isn’t removed from msmq and i don’t know how remove this messages from MSMQ once it been read.
thank you for your help.
December 22nd, 2008 at 7:39 pm
Hi cbw, I know that in the new WebORB 3.6 (this example is created with 3.5) WebORB would add logic to configure the message that is sent to the queue.
I’m not sure but I think that in the WEB-INF\flex\messaging-config.xml you can configure this using the queueFactory tag.
With this queueFactory you can configure a message with an expiration time/date an other things.
I don’t think this feature comes with the free commercial edition.
January 10th, 2009 at 7:21 pm
Thank you!
March 5th, 2009 at 2:10 am
Awesome articles you have here. I’ve been using weborb too and it’s hard to find examples and documentation. Your blog is a wonderful resource!!! Congratulations. Bookmarked!
April 15th, 2009 at 3:53 pm
This is very up-to-date information. I think I’ll share it on Digg.
April 15th, 2009 at 5:55 pm
Please do so! Thx.
October 6th, 2009 at 1:09 pm
Hi,
I’ve been implementing the example MSMQ data push example, and using your help here, I can see that my MSMQ has messages added to it, and I can also see my weborbee.exe receiving a connection from Flex, BUT, the two never seem to connect. i.e. Flex never receives a message indicating that the queue has something available. How can I debug further to find why weborbee never notifies Flex of the the queue items waiting?
Thanks
Mark
October 6th, 2009 at 4:24 pm
Hi Mark, it has been a while since I’ve worked on messaging but I’ll try to give you what I got. In the beginning I also worked with that weborbee.exe and had some trouble with it. Are you using the weborb installation site or have you created a custom site with weborb enabled? I think the weborbee.exe will open a connection on port 2037. So if you have created your own custom site application and allready browsed to the weborb installation site (to look at examples for instance), then the port 2037 is already taken. I don’t know if you can follow me. You should try to restart IIS before running your example.
Does the example in the weborb installation work?
I do not work with the weborbee.exe, instead I start the RTMPServer for WebORB in the Application_Start of the global.asax (there are also examples on this in the weborb installation I think).
void Application_Start(object sender, EventArgs e)
{
try
{
Weborb.Config.ORBConfig config = new Weborb.Config.ORBConfig();
String name = “default”;
int port = Convert.ToInt32(ConfigurationManager.AppSettings["WebORBMessagingPort"]);
int backlog = 500;
log.Info(“Starting RTMPServer(” + name + “, ” + port + “, ” + backlog + “, ” + config.ToString());
Weborb.Messaging.RTMPServer server = new Weborb.Messaging.RTMPServer( “default”, port, 500, config );
server.start();
Application[ "weborbMessagingServer" ] = server;
//Weborb.Util.Logging.Log.removeLogger(“default”);
}
catch( Exception exception )
{
log.Error(“Application_Start”, exception);
}
}
Even if you use the global.asax, restart IIS before running the example.
Answer some of the questions and maybe I can be a little more specific.
If you go to http://localhost/weborb30/weborbconsole.html , you should try the example Flex Messaging With MSMQ. If that’s working, then we should be able to find a solution.
October 6th, 2009 at 8:38 pm
Thx for the help.
I am using the weborb installation site. I tried going into global.asax and commenting out the Weborb.Messaging.RTMPServer start command. Then I ran weborbee -port 2037 after restarting IIs, but it made no difference, still nothing.
Re the Weborb installation example:
I tried the ‘flex message with MSMQ’ example (the one with the drawing board and text panels) and it worked great. I even checked the MSMQ and could see the messages and the queue listed.
I guess I don’t realy understand what weborbee is doing and what the server.start is doing from within the global.asax. Why do we need weborbee if we can start a server from global.asax?
Anyway, having said all that, I’m no closer to a solution, and the strange thing, is that I simply copied the example code for Data Push.
October 6th, 2009 at 10:17 pm
I think the weborbee.exe is created by weborb to be independent of local settings in IIS, ASP.NET, … In the weborbee.exe they start the rtmp server. I usely create a new site in IIS and copy the necessary files from weborb into the site (but not the weborbee.exe). Then run diagnostics.aspx to see if everything is ok. If ok, run the weborbconsole. At the top you can check whether messaging is activated. Messaging should be activated with the code in global.asax (you can set a breakpoint to check).
I had your problem in the past. In my case I had a different site set up with weborb. First I went to the weborb installation site. The weborbee.exe was started and port 2037 was used. If I ran the example in my custom site, the same thing happened as in your case. Apparently both sites could sent messages to MSMQ but only the first started (weborb installation site) was listening if new messages were added.
Maybe you can send me your example and I’ll have a look at it.
You copied the example code for Data Push out of the example weborb provided? Or my example?
October 7th, 2009 at 12:54 pm
I copied the example from http://www.themidnightcoders.com/products/weborb-for-net/developer-den/technical-articles/data-push-from-msmq-to-flex-consumers.html
So the webor-services-config has this entry:
and the mesaging-config has this code:
.\private$\weborb-mqpush
0
0
00000000-0000-0000-0000-000000000000
WebORB MessageQueue for Messages from Windows client
4294967295
false
4294967295
Then in global.asax I have:
void Application_Start(object sender, EventArgs e)
{
try
{
Weborb.Config.ORBConfig config = new Weborb.Config.ORBConfig();
Weborb.Messaging.RTMPServer server = new Weborb.Messaging.RTMPServer( “default”, 2037, 500, config );
server.start();
Application[ "weborbMessagingServer" ] = server;
}
catch( Exception )
{
}
}
and all the rest of the code is exactly untouched from the Midnight coders example.
October 7th, 2009 at 1:55 pm
Ooops. Looks like I have to do some formatting magic to post code here properly.
October 17th, 2009 at 12:05 pm
Hi Mark, already found a solution to your problem? Last week I ran into an email from a year ago where we had the same problem. However, it was a problem we had in the network of a customer. We still haven’t found what the problem is nor a solution. I think however that your problem is different from the one at our customer. If the examples from weborb are working, then you are doing something wrong. I really suggest setting up a new site in iis with weborb in it (but not the weborbee.exe) and trying this example (this blogpost).
If, before you run your example, you surfed to the weborb examples on your localhost, then the port 2037 will be blocked. You’ll need to restart iis and in Task Manager end the w3wp.exe processes (if an example is not working I suggest to do this before giving up on your example). I’m talking about what to do in Vista, maybe on XP the process has another name.
Greetz
October 21st, 2009 at 9:46 pm
Hi,
OK, I have finally got things working, but this leads to the next problem/question. Oh, and first, I should say that I’m not totally sure what I did. For a while I was missing weborb-services-config.xml in the Flex compile option and then later I found that if there was a bad message in the queue, then nothing would happen. Deleting the queue and restarting with an empty Q solved that. However, this leads to my next question: How does WebOrb know which messages to pull from the queue? Initially I was writing an object that I defined in C# into the Queue. When I look at this message body in the queue, it has a header and a char count as well as the actual data. Where does this extra header come from? I’m asking because I am now writing into the Queue from a Perl program, and all the Perl writesis a simple string of data. WebOrb refuses to process this message and never sends it to my Flex Consumer.
The whole business of registering an alias in Flex of a C# object and how that relates to the queue is very mysterious and I don’t know how it works.
My big goal in life has been to kick off a Perl batch program that runs for about 10 minutes and writes various progress status messages. These messages I wanted to appear in a Flex window as they occur. So I have Flex calling C# which kicks off the Perl and then Perl writes to the MSMQ. But then it all stops, as Weborb won’t process the message. Is there some secret spec for fomatting msgs for Weborb?
Cheers
October 22nd, 2009 at 5:41 pm
I think that’s the main difference with our way of working. We do not use the weborb-services-config.xml in the Flex compile option. I know the examples from weborb use this, but it’s not necessary. In my examples you can see how it’s done without the Flex compile option. We do not use it because it is compiled with the code into an swf, so if you change it, you have to compile it again. We use Spring Actionscript to configure everything.
To answer your question I’ll give you a link that somehow does what you are doing but not with a Perl program (it’s a Windows Form Application). See link. Here Flex subscribes to a certain queue and the Windows Form Application pushes messages into the queue. They finally arrive in Flex, so it’s certainly possible. I once tried the example and it worked.
How does WebOrb know which messages to pull from the queue? The queues that WebOrb listens to are configured in one of the xml files in WEB-INF. I don’t know how WebOrb does it in code because it’s a black box. If you’d like to know in terms of source code how it’s being done, you’d have to check FluorineFx, the open source alternative that works somehow the same.
January 9th, 2010 at 7:24 pm
It seams I have discovered a bug in the WebORB. The applet I’m developing subscribes to one of the 10 existing sub queues. Depending on the user actions, the applet changes the queue it’s subscribed to. After it has changed the sub queue for let’s say 30 times, the WebORB stops responding, along with IIS, so I have to restart the whole darn thing.
Since the example provided by The Midnight Coderers didn’t prove to work I tried also to implement your solution. Again without success.
Here are my two Functions which do the job of un/subscribing:
private function msmqUnSubscribe():void {
if(this.mqConsumer) {
this.mqConsumer.removeEventListener( MessageEvent.MESSAGE, mqConsumer_onMessage );
this.mqConsumer.removeEventListener( MessageFaultEvent.FAULT, onMessageFault );
this.mqConsumer.channelSet.disconnectAll();
this.mqConsumer.unsubscribe();
this.mqConsumer.disconnect();
this.mqConsumer = null;
}
}
private function msmqSubscribe():void {
var subQueue:String = this.aPages.getItemAt(this.iActivePage)["page"];
var cs:ChannelSet = new ChannelSet();
var uri:String = “rtmp://{server.name}:2037/”;
var channel:WeborbMessagingChannel = new WeborbMessagingChannel(subQueue, uri);
channel.addEventListener(MessageEvent.MESSAGE, onMessage);
cs.addChannel(channel);
this.mqConsumer = new WeborbConsumer();
this.mqConsumer.destination = “ttx”;
this.mqConsumer.channelSet = cs;
this.mqConsumer.addEventListener( MessageEvent.MESSAGE, mqConsumer_onMessage );
this.mqConsumer.addEventListener(MessageFaultEvent.FAULT, onMessageFault);
this.mqConsumer.subqueue = subQueue;
this.mqConsumer.subscribe();
}
Here’s also the WebORB configuration stuff:
.\private$\[destinationName]
0
0
00000000-0000-0000-0000-000000000000
WebORB MessageQueue for Messages from Windows client
4294967295
false
4294967295
I don’t know what else to do but instead of using MSMQ to periodically probe the server…
January 17th, 2010 at 12:01 pm
I must say we also had a lot of problems with messaging. Question is if it has anything to do with WebORB or if it’s a problem with IIS, firewalls, Flex sdk, … Can’t help you on this one. As WebORB is a black box, it’s difficult to debug anything. Maybe you can ask your question on the WebORB Mailing List.