This blog has moved, permanently, to http://software.safish.com.

Monday, November 23, 2009

nServiceBus - The Good and the Bad

We've been using nServiceBus at work for the last week or two to send messages between a client and server in a (hopefully) robust fashion.

As a tool, I really like nServiceBus. Once you have it up and running, the use of MSMQ is just brilliant - force a crash in your application and when you start up again they're just there still, ready to be processed - right out the box. Wrap them in a transaction (MSMQ supports MSDTC) and anything goes wrong, the sending of the message gets rolled back. Awesome stuff - it's definitely something I will use again.

But that's not the point of this post. I'm going to point out all the BAD stuff - in the hope that someone else doesn't have the same fights I did. Let me say upfront that I recommend using it - just be aware that the document isn't just bad, it's DISMAL. The author seems to assume that we all understand how the bus works and how to use it - methods are undocumented and even the documentation on how to get it up and running is hopelessly inadequate. So, here goes.

Configuration

The nServiceBus site does have some documentation regarding publish/subscribe scenarios at http://www.nservicebus.com/PubSubApiAndConfiguration.aspx. However, the way it's worded just didn't make sense to me, and it was Rohland who finally worked out what the hell they mean.

Exhibit A

<MsmqTransportConfig
    InputQueue="myqueue"
    ErrorQueue="errors"
    NumberOfWorkerThreads="1"
    MaxRetries="5"
  />
The above configuration specifies the INPUT to your assembly's message handler. In this example, the application using this configuration will listen for messages on the MSMQ "myqueue" on the local machine. It will NOT place messages on that queue - this is the queue it will pick messages up from.

Exhibit B

  <UnicastBusConfig DistributorControlAddress="" DistributorDataAddress="">
    <MessageEndpointMappings>
      <add Messages="My.Messages" Endpoint="somequeue" />
    </MessageEndpointMappings>
  </UnicastBusConfig>
This configuration specifies where your application will publish messages TO! In this example, any messages in the "My.Messages" assembly will be placed on the "somequeue" MSMQ on the local machine. You can specify message types instead of assemblies if you want to. I quite like this - it makes it very easy to publish different messages to different queues, and it's all configurable. Also note that the end point doesn't have to be local - you can specify remote machines as per the nServiceBus documentation.

Message Handlers

In order to receive messages, your assembly that handles those messages needs to incorporate a message handler class, with support for the message types you want to receive. For example, if you want to subscribe to message types "A" and B", you can create a message handler like so:
public class MessageHandler : IMessageHandler<A>, IMessageHandler<B>
{
    public void Handle(A message)
    {
        // handle messages of type A
    }

    public void Handle(B message)
    {
        // handle messages of type B
    }

}


You don't hook this class up anywhere - nServiceBus will find it and instantiate it. I don't like that. It makes it really easy to make mistakes - make a typo on your namespace and your event handler is never invoked, and you sit there scratching your head wondering why until you finally realise your config is fine, and your typing sucks. Another downer is that this is running on a separate thread to your application, so you need to invoke a delegate on appplication's main thread to handle the code, which can be a little iffy in forms development - you need to write code like the following to get a handle on the form that you want to use, like so:
FormMain fm = FormMain.GetInstance();
fm.Invoke(fm.AddInboundMessageHandler, message);


Enumerations and/or More Complex Data Structures

One problem I found, when using version 1.9, was when sending an enumeration of custom objects via a message. My message class contained an array of custom objects, which themselves had two properties: a string property and a byte array property. Nothing complex here. However, when I picked up the message on the subscriber, the collection was there, with the correct number, but the properties of the objects in the array were always null. I just couldn't get this to work at all. Converting the array to a dictionary was even worse - I got exceptions from nServiceBus, which seemed to fall over on some rather dodgy reflection code.

One thing I did find out is that your sub-entities do need to have a default, parameterless constructor, which makes sense as nServiceBus needs to recreate the serialized objects from the queue on the other end. However, try as I might, I never got this working on 1.9. Upgrading to version 2.0, however, and it all started working. I did try converting my array into a typed list for convenience, but this didn't work off the bat and wasn't that important to me so I reverted back to an array.

That's all I can think of for now - I'm sure I'll update this post in the future.

References When I started looking at this there was NOTHING out there - but people are certainly using it. Her are some decent articles on nServiceBus:

Monday, November 16, 2009

MS DTC Timeout error

I had a very frustrating Friday evening fighting with MSDTC. I made a one-line, 10 second change to a page I was working on. It was one of those things that you really don't even need to test usually, but I always test, no matter how small the change, and 2.5 hours later I was still pulling my hair out. I just kept getting MSDTC timeout exceptions.

Now, this was a page that had been working literally hours before, with no other code changes. The ONLY difference I could think of, was that I had applied windows updates to my machine - but this turned out to be a red herring. The same page, with the same code, worked on a colleague's machine. I checked settings, triple checked settings, flushed my DNS cache, restarted my machine, all to no avail. Comment out the TransactionScope - it all worked fine, put it back in, boom!

Anyway, in case this happens to anyone else ever - this turned out to be a DNS issue on the SERVER. Logging into the server I could ping my machine by IP, but pinging by host name failed. Finally, I was getting somewhere. It turned out there was a dodgy DNS entry - flushing the DNS cache on the server worked and everything returned to normal. What a waste of 2.5 hours.

Friday, November 13, 2009

Moq :: Ignoring Arguments

I've always used Rhino Mocks as a mocking framework, but at work we recently made the decision to give Moq a try.

My initial reaction is: WOW! It is just SO much easier to use. I've always found the setting up of mocks and verification of method calls a tedious task, but using Moq I've actually found it's really simple. It's a far more intuitive framework, and once I've got around my Rhino Mock habits, I've really found that the amount of code required for mocking is drastically reduced.

One very simple thing that stumped me today though, was trying to verify a method was called, but telling Moq to ignore the argument that was passed. In this case Rhino Mocks is a little more intuitive - it has an IgnoreArguments() method that chains off the setup. In the end though, the Moq implementation is actually easier - you just make your Setup or Verify call and use the "It" class to generate your stub.

In my example:
  myMockedClass.Verify(x => x.Connect(It.IsAny<MyArgumentType>()));