NServiceBus Unobtrusive Conventions DefiningCommandsAs multiple times

518 Views Asked by At

It seems that I cannot define commands/events conventions more than once. Every registered convention will override previous.

This works:

 configuration.Conventions()
            .DefiningCommandsAs(
                type => type.FullName == "MyProject1.CommandA" || type.FullName == "MyProject2.CommandB");

But this doesn't:

        configuration.Conventions()
            .DefiningCommandsAs(
                type => type.FullName == "MyProject1.CommandA");

        configuration.Conventions()
            .DefiningCommandsAs(
                type => type.FullName == "MyProject2.CommandB");

Why do I need this:

I'm developing a package that once referenced in NSB project will perform periodic actions (send messages). It needs to define own command conventions in INeedInitialization which will be picked up during assembly scanning. I don't want the user of the package to know that he needs to register conventions of the package. However the host project needs to register own conventions for commands. So it seems at the moment I either need to resort to Marker interfaces (which I don't want to do, there is a good reason why Unobtrusive mode was introduced) or come up with conventions like all commands must reside in *.Commands.* namespace which I don't like either.

So the questions is how to make package register it's own conventions unobtrusively and transparently to the Host.

Edit

Another way I can think of hacking around this is implementing a shared convention singleton and delegate registration of conventions to it. That singleton will then remember all conventions and will keep appending them every time. Not beautiful, but not uglier than other 2 options.

1

There are 1 best solutions below

2
David Boike On

Message conventions not supporting multiple calls is definitely by design. This is to prevent having multiple opinions on what a message might be. Having them be additive implies that anybody can have an opinion.

So this pattern is meant to provide friction against just that, to get you to agree on one definition of what Command means inside the entire system. Basically, SOA Tenet #4: Service compatibility is based upon policy. A lot of times this is the "namespace ending in .Commands" pattern; I've used that one personally and it works well.

I do work for Particular, so while nothing is ever set in stone, I can be reasonably confident in saying there are no plans to change this in V6.

If you absolutely need to do something different, your idea in your Edit of creating some sort of MessageRegistry singleton and having the convention delegate to MessageRegistry.IsCommand(Type) is perfectly valid. In V5 nothing will be executed until the bus starts so as long as the MessageRegistry is filled before the bus starts (which could also be accomplished from within INeedInitialization) then everything should work great.

If you do go down that route I'd encourage you to go all the way and have your registry singleton responsible for other metadata like TimeToBeReceived, DataBus, WireEncryptedString, Express, and any other attribute-based message metadata as well.