rowmark
rowmark

Reputation: 237

Reading MSMQ messages from VB.net Windows Service

How can I read MSMQ messages from a VB.net Windows Service written in VB.net 2008. The messages in MQ contains XML data. I need to read that XML using LinQ to XML, Validate against XSD.

I would really appreciate if you can direct me to a sample

Thanks

Upvotes: 0

Views: 2515

Answers (2)

I just wrote this exact thing, but since I bound my messages to a concrete class, the validation is automatic. Mind you, when you send an object in MSMQ as a message, it is still 'reduced' to XML... So in a way, I guess I'm doing what XSD would do, but in a much simpler way.

The 'service' part is probably irrelevant here, but I use services as both senders, receivers, and parsers for MSMQ.

Here is how I shepherd an object in MSMQ:

To understand reading, you need to understand how to send the object (XML, Class, whatever):

Note: SyslogEntry is a POCO with attributes for each part of a normal syslog/UDP514 message. No logic in that class.

Public Sub SendMessage(syslogEntry As SyslogEntryLibrary.syslog.SyslogEntry, qPath As String)
    Try
        ' Connect to a queue on the local computer. 
        Me.TheQ = New MessageQueue(qPath)
        ' make all messages recoverable
        Me.TheQ.DefaultPropertiesToSend.Recoverable = True
        ' Create a new message. 
        Me.MsgTo = New Message(syslogEntry, New XmlMessageFormatter(New Type() {GetType(SyslogEntryLibrary.syslog.SyslogEntry)}))
        With Me.MsgTo
            .AcknowledgeType = AcknowledgeTypes.PositiveReceive Or AcknowledgeTypes.PositiveArrival
            ' .Body = syslogEntry
            .Priority = MessagePriority.Normal
        End With
        ' set what will be sent with message...
        TheQ.MessageReadPropertyFilter.ArrivedTime = True
        TheQ.MessageReadPropertyFilter.SentTime = True
        TheQ.MessageReadPropertyFilter.CorrelationId = True
        TheQ.MessageReadPropertyFilter.Id = True
        TheQ.Formatter = New XmlMessageFormatter(New Type() {GetType(SyslogEntryLibrary.syslog.SyslogEntry)})
        TheQ.Send(MsgTo)
    Catch ex As Exception
        [...]
    End Try
    Return

The only interesting part of the above is this:

Me.MsgTo = New Message(syslogEntry, New XmlMessageFormatter(New Type(){GetType(SyslogEntryLibrary.syslog.SyslogEntry)}))

I am telling MSMQ the exact format the sent message will take, so it can break it up into XML for me in the Body of the Message. Oh, and one other thing, I try not to instantiate any objects when sending or receiving messages (preferring to re-use a class level variable) purely for speed & resources considerations. That is why you see things like "Me.TheQ", "Me.MsgTo", etc. No idea if this matters, but it's a practice/habit I've had for years... :)

Anyway, a typical message of this class looks like this:

enter image description here

You can see the class name, and some of the schema definitions in the Body. I have nothing to do with it-it's all done for me (with Reflection) :)

So now that my message (instance of a class, really) in on the queue, it's time to grab it from another program (maybe a service?) and reconstitute it!

Public Function ReceiveMessage(qPath As String) As SyslogEntryLibrary.syslog.SyslogEntry
    Dim sysEvent As SyslogEntryLibrary.syslog.SyslogEntry = Nothing
    Try
        ' Connect to the a queue on the local computer. 
        Me.rcvQueue = New MessageQueue(qPath)
        Me.rcvQueue.MessageReadPropertyFilter.CorrelationId = True
        ' Set the formatter to indicate body contains a SyslogEntry instance
        Me.rcvQueue.Formatter = New XmlMessageFormatter(New Type() {GetType(SyslogEntryLibrary.syslog.SyslogEntry)})
        ' Receive and format the message.  
        Dim myMessage As Message = Me.rcvQueue.Receive()
        sysEvent = CType(myMessage.Body, SyslogEntryLibrary.syslog.SyslogEntry) 
    Catch ex As InvalidOperationException
        [...]
    Catch ex As Exception
        [...]
    End Try
    Return sysEvent
End Function 'ReceiveMessage

So just like before, the magic happens in these lines:

Me.rcvQueue.Formatter = New XmlMessageFormatter(New Type(){GetType(SyslogEntryLibrary.syslog.SyslogEntry)})

Dim myMessage As Message = Me.rcvQueue.Receive()

sysEvent = CType(myMessage.Body, SyslogEntryLibrary.syslog.SyslogEntry)

I have seen examples that use XML as the body, and even just a string, so I'm sure you can play with this as you see fit.

Still, without understanding what you are trying to do, you'll forgive me if I suggest you stick with POCOs in your business logic, and let lower level tools like MSMQ do all the XML formatting for you. One thing I hate doing it writing XML in code 'manually'. :)

I hope this gives you a few ideas!

Upvotes: 0

Chris Pitman
Chris Pitman

Reputation: 13104

I would suggest looking into WCF using the MsmqIntegrationBinding. I've recently done the same (except using the netMsmqBinding since I was not integrating with a pre-existing system), and it has worked out very well. For samples, you should look at the WCF Samples provided by Microsoft.

Upvotes: 4

Related Questions