Using message inheritance

584 views
Skip to first unread message

Claus Nielsen

unread,
Aug 23, 2011, 8:53:13 AM8/23/11
to masstrans...@googlegroups.com
I'm using MassTransit as a way to make two processes communicate, and would like to share a perhaps big model base.
My question is then, if it is possible to use inheritance for messages?

Currently I'm trying to create a consumer "DataRequestHandler", which is supposed to handle all BaseData types. When I publish a message of type Messages.Data.TodoList (which enherits from Messages.Data.BaseData), I never enter my Consume method of the consumer instance. 

Consumer looks like:
internal class DataRequestHandler : MassTransit.Consumes<Messages.DataRequest<Messages.Data.BaseData>>.All

Publisher publishes via:
MassTransit.Bus.Instance.Publish(new Messages.DataRequest<Messages.Data.TodoList> { Id = id }, (c) => { });

If I publish a message of type Message.Data.BaseData or use Messages.Data.TodoList in the consumer, it all works. 

So, is it not possible to use inheritance when sending messages?

A current solution is to create a generic "DataRequestHandler<T>" and register the data handler for each type, but I would prefer to use inheritance (maybe even with generics)..

Thanks!

Dru Sellers

unread,
Aug 23, 2011, 10:05:25 AM8/23/11
to masstrans...@googlegroups.com
Greetings Claus,

Bottom Line: Inheritance will work in MassTransit - We use it in our Subscription management code.

WARNING: Generics in Message classes will work, but neither Chris or I use this feature extensively, nor do we test for it extensively. You are getting close to a very sharp edge in MT, and you may end up cutting yourself on it.

That said, I would advise you to think about the following things:
1. Message Design is not OO Design (A message is just state, no behavior) There is a greater focus on interop and contract design.
2. As messages are more about contracts, we suggest subscribing to interfaces that way you can easily evolve the implementation of the message.
3. A big base class may cause pain down the road as each change will have a larger ripple. This can be especially bad when you need to support multiple versions.
4. I would avoid naming the base type 'BaseData' (which has no business meaning) and would instead opt for something that would make more sense in the context of a discussion with the business.
5. What is it you are trying to optimize for? By using a large base class.



Comments:
- I don't recommend subscribing to a base type, if you later plan to cast to another type..
- Be wary of your code if you start to see 'type' checks in it. Such as if(msg is TodoList) { /* do stuff */ }. I usually try to avoid the base types except for minimal administrative items like a common message id.
- Again, use inheritance sparingly. Composition is usually a much better path.


-d


--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To view this discussion on the web visit https://groups.google.com/d/msg/masstransit-discuss/-/ApucT8FIHpAJ.
To post to this group, send email to masstrans...@googlegroups.com.
To unsubscribe from this group, send email to masstransit-dis...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/masstransit-discuss?hl=en.

Travis Smith

unread,
Aug 23, 2011, 10:07:56 AM8/23/11
to masstrans...@googlegroups.com
If you subscribe to "BaseData" and then hope to cast to a type is a
child type of it, it will fail. Our serializer does not contain type
information in the data and will only build an implementation of the
exact type (or implementation of that type if it's an interface) that
you subscribe to.

This might not matter to you, just wanted to make sure you were aware.

-Travis

Claus Nielsen

unread,
Aug 24, 2011, 4:33:36 AM8/24/11
to masstrans...@googlegroups.com
Hello Dru

FYI, the BaseData object is empty, so it's not the object that are big, its the object model.
Each type might not contain much information as a message type, but the type is important.

What I mean is, the purpose of the request is to send a data request to a framework. A Messages.Data.DataRequest states that a client would like a response of this or that type. At some point I need to test for that type, whether I use generics or a Type property. 

My question was regarding the need for a consumer of all the types in my object model, or if I could just use the base class as consumer. Unfortunately it does not seem so?

Med venlig hilsen | Best regards
Claus Nielsen

Chris Patterson

unread,
Aug 24, 2011, 8:39:36 AM8/24/11
to masstrans...@googlegroups.com
Rather than checking the type, you need to register a subscription for each type.

Then you don't have to switch on the empty base type, the framework does all the work for you and calls the proper handler with the already closed type.

You may have:

interface A {}
interface B : A {}
interface C : A {}

And if you publish a message class that implements B or C, you would get called with a B or C to the proper handler.

class MyConsumer : Consumes<B>.All, Consumes<C>.All {
    void Consume(B message);
    void Consume(C message);
}

That way you don't have to bother typing the message yourself, it's already done for you. It's explicit, and it's a contract between the message producer and the message consumer. By trying to "type" a message in the consumer, you are putting implicit assumptions on the message contract, which is real fun when somebody else tries to maintain the code a year later. And by real fun, I am making joke.

Claus Nielsen

unread,
Aug 24, 2011, 8:57:51 AM8/24/11
to masstrans...@googlegroups.com
This is good stuff, I'll try that! Thanks!

Med venlig hilsen | Best regards
Claus Nielsen


Udi Dahan

unread,
Aug 24, 2011, 7:50:40 PM8/24/11
to masstrans...@googlegroups.com

Dru,

 

I usually recommend against message composition as it ends up pushing users in the direction of trying to do content-based routing from within the bus – leading to very broker-centric architectures.

 

Cheers,

 

Udi


No virus found in this message.
Checked by AVG - www.avg.com
Version: 10.0.1392 / Virus Database: 1520/3853 - Release Date: 08/23/11

Dru Sellers

unread,
Aug 24, 2011, 7:54:15 PM8/24/11
to masstrans...@googlegroups.com
Excellent. Ok. Should I read into this then that you are PRO inheritance? or that you are ANTI composition (in messages) and ANTI inheritance??

-d

-d

Udi Dahan

unread,
Aug 24, 2011, 8:52:30 PM8/24/11
to masstrans...@googlegroups.com

Interface-based inheritance is OK, not so crazy about inheritance with classes.

Version: 10.0.1392 / Virus Database: 1520/3855 - Release Date: 08/24/11

Dru Sellers

unread,
Aug 24, 2011, 8:53:04 PM8/24/11
to masstrans...@googlegroups.com
I can get behind that.

-d

Travis Smith

unread,
Aug 24, 2011, 9:16:52 PM8/24/11
to masstrans...@googlegroups.com, masstrans...@googlegroups.com
That seems in line with how I feel about it. Chris has done some great work on consumers for interfaces and building implementations of them. 

-Travis

Claus Nielsen

unread,
Aug 25, 2011, 3:06:23 AM8/25/11
to masstrans...@googlegroups.com
So what exactly are you suggesting? That I create interfaces of the same objects, and then use the same approach?

The objects are all DTO's, so they are rather stupid.
It is also transparent to the user, that a bus even exists, so I control the message composition and usage (To a certain point :)).

Med venlig hilsen | Best regards
Claus Nielsen


Dru Sellers

unread,
Aug 31, 2011, 4:06:00 PM8/31/11
to masstrans...@googlegroups.com
@Udi,

so, the message should only be primitive types?

or

can we have a composite type as a child class, but JUST DON'T share them between message types???

-d

Udi Dahan

unread,
Aug 31, 2011, 10:49:08 PM8/31/11
to masstrans...@googlegroups.com

I’d say that going for only primitive types could be a bit too restrictive but this problem could be found most with events (rather than commands), where you might have multiple subscribers that each would only want to receive a subset of the stream based on some property of the event.

 

Hope that makes sense,

Version: 10.0.1392 / Virus Database: 1520/3868 - Release Date: 08/30/11

Reply all
Reply to author
Forward
0 new messages