2

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.

Sergej Popov
  • 2,933
  • 6
  • 36
  • 53
  • Sorry, I don't think there are any options here beyond the two you mentioned (markers and commands namespace). I would go with the .commands namespace convention personally. – Tyler Day Dec 10 '15 at 16:02
  • @TylerDay thanks, that's what I have suspected. Any clue if Particular plans to fix this in v6? – Sergej Popov Dec 10 '15 at 16:24
  • That I don't know, but if I had to guess I would say this is probably by design and not a bug. It would be a nice feature to have though. – Tyler Day Dec 10 '15 at 16:43

1 Answers1

5

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.

David Boike
  • 18,545
  • 7
  • 59
  • 94
  • David, thanks for your clear answer, I was trying to figure out how did you achieve that in your own ServicePulse Heartbeats? `EndpointHeartbeat` command is not marked with interface, nor it is in some .Commands namespace. Is there some internal trickery? https://github.com/Particular/ServiceControl.Plugin.Nsb5.Heartbeat – Sergej Popov Dec 10 '15 at 20:15
  • We use lower-level messaging transport interfaces for ServiceControl plugin messages, so they're not included in the general pool of messages at the user code level. They're also internal classes, and you could not send an EndpointHeartbeat yourself. – David Boike Dec 10 '15 at 21:42