Friday, December 20, 2013

The Geek Christmas Quiz 2013

This is the second year of my Geek Christmas Quiz. Six sections of the ultimate geek questions. The office competition was won by Toby Carter with a score of 46. See if you can do better.

The answers are here.

Last year’s quiz is here.

What does this acronym stand for? (one point per correct answer)
    1. AWS
    2. SQL
    3. NATO
    4. GNU
    5. SCSI
    6. HTML
    7. HTTP
    8. ReST
    9. NASA
    10. RAF

Name that computer (one point for the model, another for the company/inventor)

Quiz_name_that_computer

Name that programming language (one point for each correct answer)

1.    
10 PRINT "HELLO WORLD"
20 GOTO 10 

2.    
while(true)
{
    Console.WriteLine("Hello World");
} 

3.    
for(;;) {
    printf("Hello World");
} 

4.    
let rec hello () =
    printfn "Hello World"
    hello() 

5.    
while true
    writeln ("Hello World") 

6.    
WHILE 1 = 1 PRINT "Hello World" 

7.    
while /bin/true; do echo -n 'Hello World!'; done; 

8.    
(while true (print "hello world")) 

9.    
let hello = do putStr "Hello World"; hello 

Science fiction (one point for each correct answer)

    1. "These are not the droids you are looking for" (what film?)
    2. "Open the pod bay doors please HAL" (what film, or book?)
    3. Who wrote Rendezvous with Rama?
    4. What spaceship uses dilithium crystals
    5. what does the acronym CREW in Iain Bank's culture novels mean when referring to weapons
    6. Name 3 futurama characters
    7. Who wrote the 3 laws of robotics?
    8. What is the first law of robotics?
    9. Who is the leader of the Daleks?
    10. Directive? (which film?)

Science (one point for each correct answer)

    1. 1 degree fahrenheit is a different size to 1 degree centigrade which means they must cross at some point. At what temperature are both scales the same?
    2. When and where was the first cell in your body created?
    3. What is the device which blends air and fuel in an internal combustion engine called?
    4. What was the name of the first hydrogen (thermonuclear) bomb test?
    5. What is special about Sirius, the Dog Star?
    6. What year did the last man land on the moon?
    7. Who invented the jet engine?
    8. In trigonometry what is calculated by dividing the adjacent over the hypotenuse?
    9. Which part of the Earth lies between the outer core and the crust?
    10. Where in the body are alveoli to be found?

Name that cartoon character (one point for each correct answer)

Quiz_name_that_cartoon_character

Tuesday, December 17, 2013

How to Run a Successful Open Source Project

A couple of months ago I attended BarCamp Brighton, an open conference at Brighton University. Everyone is encouraged to present a session, and as I don’t need much excuse to talk to a room full of people I thought I’d do an unrehearsed talk on running an open source project based on my experiences with EasyNetQ. I spent about half an hour going through what EasyNetQ is, its history, and how I organise things, to a room of six people. I know, fame at last! The really interesting bit came during the questions when I got into a discussion with a chap who worked for the Mozilla foundation. He asked what makes a successful open source project. Of course ‘success’ is very subjective. Success for me means that some people are interested enough in EasyNetQ to download it from NuGet and commit time to sending me bug reports and pull requests, for other people success might be defined as a project so popular that they can make a living from supporting it. Given the former, lower bar, here are some of the things that we came up with.

  • It has to do something useful. Obvious, yes. The classic ‘scratching an itch’ reason for starting an OSS project usually means that it’s useful to you. How successful your project will be depends on how common your problem is.
  • A clear mission. If you have a clear mission, it’s easy for people to understand the problem you are trying to solve. EasyNetQ’s mission is to provide the simplest possible API for RabbitMQ on .NET. People know what the intention is, and it provides a guide to EasyNetQ’s design.
  • Easy to install. If your environment provides a package manager, make sure your project provides a package for it. Otherwise make sure you provide a simple installer and clear instructions. Don’t insist that people build your project from source if you can avoid it. EasyNetQ installs from NuGet in a few seconds.
  • A good ‘first 20 minutes’ experience. Make your project super easy to get started with. Have a quick start guide to help users get something working as soon as possible. You can get EasyNetQ up and running with two console apps publishing and subscribing within 10 minutes. Hmm, I need to get that quick start guide done though :p
  • Documentation! Clear, simple to follow, documentation is really helpful to your users. Keep it up to date. A wiki that anyone can update is ideal. I use the GitHub wiki for EasyNetQ’s documentation. If you can register a domain name and have a nice homepage with a short pithy introduction to your project, so much the better.
  • A forum for communicating with your users. I use a Google group. But there are many other options. Make sure you answer people’s questions. Be nice (see below).
  • Let people know what’s happening. A blog, like this, is an ideal place to write about the latest project news. Let people know about developments and your plans for the future.
  • Release early, release often. Long feedback loops kill software. That’s true of any project, open or closed, but much more so for open source. The sooner you get your code in front of people, the sooner you find out when it isn’t working. Have a continuous build process that allows people to be able to quickly install the very latest version. You can split out ‘stable’ from ‘development’ releases if you want. I don’t bother, every commit to EasyNetQ’s GitHub repository is immediately published to NuGet, but that will probably change as the project matures.
  • Have a versioning policy and explain it. You can see EasyNetQ’s here.
  • Use GitHub to host your source code. Yes, yes, I know there are alternatives, but GitHub has made hosting and contributing to OSS projects much easier. It has become so ubiquitous that it’s the obvious choice. Everyone knows how it works.
  • Be nice! It’s easy to get frustrated with weird questions on the mailing list, or strange pull requests, but always remember to be polite and helpful. Be especially nice to people who send you bug reports and pull requests, they are helping your project for no gain. Be thankful.

I’m sure there are loads of other things that I’ll think of as soon as I hit ‘publish’ on this post, so don’t think of this as comprehensive. I’d love to hear any more suggestions in the comments.

Of course the main problem most people have to overcome with running an OSS project is finding the time. I’ve been extraordinarily fortunate that 15below have sponsored EasyNetQ. If you use it and like it, don’t forget to thank them.

Thursday, December 12, 2013

Are Your Programmers Working Hard, Or Are They Lazy?

When people are doing a physical task, it’s easy to assess how hard they are working. You can see the physical movement, the sweat. You also see the result of their work: the brick wall rising, the hole in the ground getting bigger. Recognising and rewarding hard work is a pretty fundamental human instinct, it is one of the reasons we find endurance sports so fascinating. This instinctive appreciation of physical hard work is a problem when it comes to managing creative-technical employees. Effective knowledge workers often don’t look like they are working very hard.

Back in 2004, I was a junior developer working in a large team on a cable TV company’s billing and provisioning system. Like all large systems it was made up of a number of relatively independent components, with different individuals or small teams looking after them. The analogue TV and digital TV provisioning systems were almost entirely separate, with a different team looking after each.

The analogue TV team had decided to base their system around an early version of Microsoft Biztalk. There were four of our guys and a team from Microsoft developing it and running it in production. They all appeared to work really hard. They would often be seen working into the night and at weekends. Everyone would drop what they were doing to help with production issues, often crowding around a single guy at a desk, offering suggestions about what could be wrong, or how to fix something. There was constant activity, and anyone could see, just by looking that, not only did everyone pull together as a team, but they were all working really really hard.

The digital TV provisioning team was very different. The code had been mostly written by a single guy, let’s call him Dave. I was a junior maintenance developer on the team. Initially I had a great deal of trouble understanding the code. There wasn’t one long procedure somewhere where all the stuff happened, instead there were lots of small classes and methods with just a few lines of code. Several of my colleagues complained that Dave made things overcomplicated. But Dave took me under his wing and suggested that I read a few books on object oriented programming. He taught me about design patterns, the SOLID principles, and unit testing. Soon the code started to make sense, and the more I worked on it the more I came to appreciated its elegant design. It didn’t go wrong in production, just hummed away doing its job. It was relatively easy to make changes to the code too, so implementing new features was often quite painless. The unit tests meant that few bugs made it into production.

The result of all this was that it didn’t look like we were working very hard at all. I went home at 5.30pm, I never worked weekends, we didn’t spend hours crowded around each other’s desks throwing out guesses about what could be wrong with some failing production system. From the outside it must have looked like we’d been given a far easier task than the analogue TV guys. In truth, the requirements were very similar, we just had better designed and implemented software, and better supporting infrastructure, especially the unit tests.

Management announced that they were going to give out pay rises based on performance. When it was my turn to talk to the boss, he explained that it was only fair that the pay increases went to the people who worked really hard, and that our team just didn’t seem to care so much about the company, not compared to the heroes who gave up their evenings and weekends.

The cable company was a rare laboratory, you could observe a direct comparison between the effects of good and bad software design and team behaviour. Most organisations don’t provide such a comparison. It’s very hard to tell if that guy sweating away, working late nights and weekends, constantly fire-fighting, is showing great commitment to making a really really complex system work, or is just failing. Unless you can afford to have two or more competing teams solving the same problem, and c’mon, who would do that, you will never know. Conversely, what about the guy sitting in the corner who works 9 to 5, and seems to spend a lot of time reading the internet? Is he just very proficient at writing stable reliable code, or is his job just easier than everyone else’s? To the casual observer, the first chap is working really hard, the second one isn’t. Hard work is good, laziness is bad, surely?

I would submit that the appearance of hard work is often an indication of failure. Software development often isn’t done well in a pressurised, interrupt driven, environment. It’s often not a good idea to work long hours. Sometimes the best way of solving a difficult problem is to stop thinking about it, go for a walk, or even better, get a good night’s sleep and let your subconscious solve it. One of my favourite books is A Mathematician’s Apology by G. H. Hardy, one of the leading British mathematicians of the 20th century. In it he describes his daily routine: four hours work in the morning followed by an afternoon of watching cricket. He says that it’s pointless and unproductive to do hard mental work for more than four hours a day.

To managers I would say, judge people by results, by working software, not by how hard they appear to be working. Counter intuitively, it may be better not to sit with your developers, you may get a better idea of their output unaffected by conventional/intuitive indicators. Remote working is especially beneficial; you will have to measure your employees by their output, rather than the lazier option of watching them sitting at their desks 8 hours a day thumping away at an IDE, or ‘helpfully’ crowding around each other’s desks offering ‘useful’ suggestions.

Monday, December 09, 2013

EasyNetQ: Replace the Internal DI Container

logo_design_150

EasyNetQ, is made up of a collection of independent components. Internally it uses a tiny internal DI (IoC) container called DefaultServiceProvider. If you look at the code for the static RabbitHutch class that you use to create instances of the core IBus interface, you will see that it simply creates a new DefaultServiceProvider, registers all of EasyNetQ’s components, and then calls container.Resolve<IBus>() creating a new instance of IBus with its tree of dependencies supplied by the container:

public static IBus CreateBus(IConnectionConfiguration connectionConfiguration, Action<IServiceRegister> registerServices)
{
Preconditions.CheckNotNull(connectionConfiguration, "connectionConfiguration");
Preconditions.CheckNotNull(registerServices, "registerServices");

var container = createContainerInternal();
if (container == null)
{
throw new EasyNetQException("Could not create container. " +
"Have you called SetContainerFactory(...) with a function that returns null?");
}

registerServices(container);
container.Register(_ => connectionConfiguration);
ComponentRegistration.RegisterServices(container);

return container.Resolve<IBus>();
}

But what if you want EasyNetQ to use your container of choice? From version 0.25 the RabbitHutch class provides a static method, SetContainerFactory, that allows you to register an alternative container factory method that provides whatever implementation of EasyNetQ.IContainer that you care to supply.

In this example we are using the Castle Windsor IoC container:

// register our alternative container factory
RabbitHutch.SetContainerFactory(() =>
{
// create an instance of Windsor
var windsorContainer = new WindsorContainer();
// wrap it in our implementation of EasyNetQ.IContainer
return new WindsorContainerWrapper(windsorContainer);
});
// now we can create an IBus instance, but it's resolved from
// windsor, rather than EasyNetQ's default service provider.
var bus = RabbitHutch.CreateBus("host=localhost");

Here is how I implemented WindsorContainerWrapper:

public class WindsorContainerWrapper : IContainer, IDisposable
{
private readonly IWindsorContainer windsorContainer;

public WindsorContainerWrapper(IWindsorContainer windsorContainer)
{
this.windsorContainer = windsorContainer;
}

public TService Resolve<TService>() where TService : class
{
return windsorContainer.Resolve<TService>();
}

public IServiceRegister Register<TService>(System.Func<IServiceProvider, TService> serviceCreator)
where TService : class
{
windsorContainer.Register(
Component.For<TService>().UsingFactoryMethod(() => serviceCreator(this)).LifeStyle.Singleton
);
return this;
}

public IServiceRegister Register<TService, TImplementation>()
where TService : class
where TImplementation : class, TService
{
windsorContainer.Register(
Component.For<TService>().ImplementedBy<TImplementation>().LifeStyle.Singleton
);
return this;
}

public void Dispose()
{
windsorContainer.Dispose();
}
}

Note that all EasyNetQ services should be registered as singletons.

It’s important that you dispose of Windsor correctly. EasyNetQ doesn’t provide a Dispose method on IContainer, but you can access the container via the advanced bus (yes, this is new too), and dispose of windsor that way:

((WindsorContainerWrapper)bus.Advanced.Container).Dispose();
bus.Dispose();

Happy containerisation!

Monday, November 25, 2013

EasyNetQ’s Minimalist DI Container

I’ve been a long time fan of IoC (or DI) containers ever since I first discovered Castle Windsor back in 2007. I’ve used Windsor in every major project I’ve been involved in since then, and if you’d gone to a developer event in the late naughties, you may well have encountered me speaking about Windsor. Indeed, Seb Lambla had the cheek to call me ‘Windsor man’. I shall label him ‘Rest-a-man’ in revenge.

When I started working on EasyNetQ in 2011, I initially thought it would be a very simple lightweight wrapper around the RabbitMQ.Client library. The initial versions were very procedural, ‘just get it done’, script-ish code burps. But as it turned into a more serious library, I started to factor the different pieces into more SRPish classes using dependency injection. At this point I was doing poor-man’s dependency injection, with an initial piece of wire-up code in the RabbitHutch class.

As EasyNetQ started to gain some traction outside 15below, I began to get questions like, “how do I use a different serializer?” And “I don’t like your error handling strategy, how can I implement my own?” I was also starting to get quite bored of maintaining the ever-growing wire up code. The obvious solution was to introduce a DI container, but I was very reluctant to take a dependency on something like Windsor. Writing a library is a very different proposition than writing an application. Every dependency you introduce is a dependency that your user also has to take. Imagine you are a happily using AutoFac and suddenly Castle.Windsor appears in your code base, or even worse, you are an up-to-date Windsor user, but EasyNetQ insists on installing an old version of Windsor alongside. Nasty. Windsor is an amazing library, some of its capabilities are quite magical, but I didn’t need any of these advanced features in EasyNetQ. In fact I could be highly constrained in my DI container requirements:

  • I only needed singleton instances.
  • The lifetime of all DI provided components matches the lifetime of the main IBus interface.
  • I didn’t need the container to manage component disposal.
  • I didn’t need open generic type registration.
  • I was happy to explicitly register all my components, so I didn’t need convention based registration.
  • I only needed constructor injection.
  • I can guarantee that a component implementation will only have a single constructor.

With this highly simplified list of requirements, I realised that I could write a very simple DI container in just few lines of code (currently 113 as it turns out).

My super simple container only provides two registration methods. The first takes a service interface type and a instance creation function:

IServiceRegister Register<TService>(Func<IServiceProvider, TService> serviceCreator) where TService : class;

The second takes an instance type and an implementation type:

IServiceRegister Register<TService, TImplementation>()
where TService : class
where TImplementation : class, TService;

These are both defined in a IServiceRegister interface. There is also a single Resolve method in an IServiceProvider interface:

TService Resolve<TService>() where TService : class;

You can see all 113 lines of the implementation in the DefaultServiceProvider class. As you can see, it’s not at all complicated, just three dictionaries, one holding the list of service factories, another holding a list of registrations, and the last a list of instances. Each registration simply adds a record to the instances dictionary. When Resolve is called, a bit of reflection looks up the implementation type’s constructor and invokes it, recursively calling resolve for each constructor argument. If the service is provided by a service factory, it is invoked instead of the constructor.

I didn’t have any worries about performance. The registration and resolve code is only called once when a new instance of IBus is created. EasyNetQ is designed to be instantiated at application start-up and for that instance to last the lifetime of the application. For 90% of applications, you should only need a single IBus instance.

EasyNetQ’s component are registered in a ComponentRegistration class. This provides an opportunity for the user to register services ahead of the default registration, and since the first to register wins, it provides an easy path for users to replace default services implementations with their own. Here’s an example of replacing EasyNetQ’s default console logger with a custom logger:

var logger = new MyLogger();
var bus = RabbitHutch.CreateBus(connectionString, x => x.Register<IEasyNetQLogger>(_ => logger));

You can replace pretty much any of the internals of EasyNetQ in this way: the logger, the serializer, the error handling strategy, the dispatcher threading model … Check out the ComponentRegistration class to see the whole list.

Of course the magic of DI containers, the first rule of their use, and the thing that some people find extraordinarily hard to grok, is that I only need one call to Resolve in the entire EasyNetQ code base at line 146 in the RabbitHutch class:

return serviceProvider.Resolve<IBus>();

IoC/DI containers are often seen as very heavyweight beasts that only enterprise architecture astronauts could love, but nothing could be more wrong. A simple implementation only needs a few lines of code, but provides your application, or library, with considerable flexibility.

EasyNetQ is open source under the (very flexible) MIT licence. Feel free to cut-n-paste my DefaultServiceProvider class for your own use.

Thursday, November 21, 2013

EasyNetQ: Non-Generic Subscribe

logo_design_150

Since it’s very first version, EasyNetQ has allowed you to subscribe to a message simply by providing a handler for a given message type (and a subscription id, but that’s another discussion).

bus.Subscribe<MyMessage>("subscriptionId", x => Console.WriteLine(x.Text));

But what do you do if you are discovering the message type at runtime? For example, you might have some system which loads add-ins and wants to subscribe to message types on their behalf. Before today (version 0.24) you would have had to employ some nasty reflection mojo to deal with this scenario, but now EasyNetQ provides you with non-generic subscription methods out-of-the-box.

Just add the this using statement:

using EasyNetQ.NonGeneric;

Which provides you with these extension methods:

public static IDisposable Subscribe(this IBus bus, Type messageType, string subscriptionId, Action<object> onMessage)
public static IDisposable Subscribe(
this IBus bus,
Type messageType,
string subscriptionId,
Action<object> onMessage,
Action<ISubscriptionConfiguration> configure)
public static IDisposable SubscribeAsync(
this IBus bus,
Type messageType,
string subscriptionId,
Func<object, Task> onMessage)
public static IDisposable SubscribeAsync(
this IBus bus,
Type messageType,
string subscriptionId,
Func<object, Task> onMessage,
Action<ISubscriptionConfiguration> configure)

They are just like the Subscribe methods on IBus except that you provide a Type argument instead of the generic argument, and the message handler is an Action<object> instead of an Action<T>.

Here’s an example of the non-generic subscribe in use:

var messageType = typeof(MyMessage);
bus.Subscribe(messageType, "my_subscriptionId", x =>
{
var message = (MyMessage)x;
Console.Out.WriteLine("Got Message: {0}", x.Text);
});

Very useful I think, and one of the most commonly asked for features.
 
Happy runtime discovery!

Monday, November 18, 2013

EasyNetQ: Send Receive Pattern

From version 0.22, EasyNetQ supports a new message pattern: Send/Receive.

Whereas the Publish/Subscribe and Request/Response patterns are location transparent, in that you don't need to specify where the consumer of the message is located, the Send/Receive pattern is specifically designed for communication via a named queue. It also makes no assumptions about the types of message that can be sent via the queue. This means that you can send different types of message via the same queue.

The send/receive pattern is ideal for creating 'command pipelines', where you want a buffered channel to a single command processor.

To send a message, use the Send method on IBus, specifying the name of the queue you wish to sent the message to and the message itself:

bus.Send("my.queue", new MyMessage{ Text = "Hello Widgets!" });

To setup a message receiver for a particular message type, use the Receive method on IBus:

bus.Receive<MyMessage>("the.queue", message => Console.WriteLine("MyMessage: {0}", message.Text));

You can set up multiple receivers for different message types on the same queue by using the Receive overload that takes an Action<IReceiveRegistration>. For example, this sets up a receive for both MyMessage and MyOtherMessage:

bus.Receive("the.queue", x => x
.Add<MyMessage>(message => deliveredMyMessage = message)
.Add<MyOtherMessage>(message => deliveredMyOtherMessage = message));

If a message arrives on a receive queue that doesn't have a matching receiver, EasyNetQ will write the message to the EasyNetQ error queue with an exception saying 'No handler found for message type <the message type>'.

Note: You probably do not want to call bus.Receive more than once for the same queue. This will create a new consumer on the queue and RabbitMQ will round-robin between them. If you are consuming different types on different Receive calls (and thus different consumers), some of your messages will end up on the error queue because EasyNetQ will not find a handler for your message type associated with the consumer on which it is consumed.

Wednesday, November 13, 2013

EasyNetQ: Multiple Handlers per Consumer

A common feature request for EasyNetQ has been to have some way of implementing a command pipeline pattern. Say you’ve got a component that is emitting commands. In a .NET application each command would most probably be implemented as a separate class. A command might look something like this:

public class AddUser
{
public string Username { get; private set; }
public string Email { get; private set; }

public AddUser(string username, string email)
{
Username = username;
Email = email;
}
}

Another component might listen for commands and act on them. Previously in EasyNetQ it would have been difficult to implement this pattern because a consumer (Subscriber) was always bound to a given message type. You would have had to use the lower level IAdvancedBus binary message methods and implement your own serialization and dispatch infrastructure.

But now EasyNetQ comes with multiple handlers per consumer out of the box.

From version 0.20 there’s a new overload of the Consume method that provides a fluent way for you to register multiple message type handlers to a single consumer, and thus a single queue.

Here’s an example:

bus = RabbitHutch.CreateBus("host=localhost");

var queue = bus.Advanced.QueueDeclare("multiple_types");

bus.Advanced.Consume(queue, x => x
.Add<AddUser>((message, info) =>
{
Console.WriteLine("Add User {0}", message.Body.Username);
})
.Add<DeleteUser>((message, info) =>
{
Console.WriteLine("Delete User {0}", message.Body.Username);
})
);

Now we can publish multiple message types to the same queue:

bus.Advanced.Publish(Exchange.GetDefault(), queue.Name, false, false, 
new Message<AddUser>(new AddUser("Steve Howe", "steve@worlds-best-guitarist.com"))));
bus.Advanced.Publish(Exchange.GetDefault(), queue.Name, false, false,
new Message<DeleteUser>(new DeleteUser("Steve Howe")));

By Default, if a matching handler cannot be found for a message, EasyNetQ will throw an exception. You can change this behaviour, and simply ignore messages that do not have a handler, by setting the ThrowOnNoMatchingHandler property to false, like this:

bus.Advanced.Consume(queue, x => x
.Add<AddUser>((message, info) =>
{
Console.WriteLine("Add User {0}", message.Body.Username);
})
.Add<DeleteUser>((message, info) =>
{
Console.WriteLine("Delete User {0}", message.Body.Username);
})
.ThrowOnNoMatchingHandler = false
);

Very soon there will be a send/receive pattern implemented at the IBus level to make this even easier. Watch this space!

Happy commanding!

Wednesday, November 06, 2013

EasyNetQ: Consumer Cancellation

Consumer cancellation has been a requested feature of EasyNetQ for a while now. I wasn’t intending to implement it immediately, but a pull request by Daniel White today made me look at the whole issue of consumer cancellation from the point of view of a deleted queue. It led rapidly to a quite straightforward implementation of user cancellations. The wonders of open source software development, and the generosity of people like Daniel, never fails to impress me.

So what is consumer cancellation? It means that you can stop consuming from a queue without having dispose of the entire IBus instance and close the connection. All the IBus Subscribe methods, and the IAdvancedBus Consume methods now return an IDisposable. To stop consuming, just call Dispose like this:

var cancelSubscription = bus.Subscribe<MyMessage>("subscriptionId", MessageHandler);
.
.
// sometime later stop consuming
cancelSubscription.Dispose();

Nice :)

Tuesday, November 05, 2013

EasyNetQ: Changes to Conventions With Version 0.18

TL:DR: Exchange and queue names used to have ‘.’ replaced with ‘_’. From version 0.18 this is no longer the case.

Yesterday I announced version 0.18 of EasyNetQ. The big change was the addition of polymorphic publish and subscribe.

I forgot to mention that there’s a slight change to the conventions that EasyNetQ uses, that might affect you when you upgrade.

EasyNetQ’s publish-subscribe pattern is implemented in AMQP as follows:

  • A topic exchange named after the published type is created.
  • A queue named by concatenating the published type and the subscriber id is created.
  • The exchange is bound to the queue with the wildcard, ‘#’, binding key.

So if you have this code:

bus.Subscribe<MyMessage>("test", MessageHandler);
bus.Publish<MyMessage>(message);

Note, in my case MyMessage is in an assembly ‘EasyNetQ.Tests’ with the same namespace.

You will see this in the RabbitMQ management UI:

img title="default_binding" style="border-left-width: 0px; border-right-width: 0px; border-bottom-width: 0px; display: inline; border-top-width: 0px" border="0" alt="default_binding" src="$default_binding5.png" width="715" height="487" />

Previously The exchange and queue names would have had the ‘.’ replaced with ‘_’: ‘EasyNetQ_Tests_MyMessage:EasyNetQ_tests’.

If you upgrade some services to version 0.18, but leave others at earlier version numbers, they won’t be able to communicate.