[rabbitmq-discuss] My attempt at a high-level API for .NET
Bryan Murphy
bmurphy1976 at gmail.com
Thu May 5 15:13:34 BST 2011
On Wed, May 4, 2011 at 11:15 AM, Mike Hadlow <mike.hadlow at 15below.com> wrote:
> I’ve just published details of a high level .NET API for Rabbit/AMQP:
>
> http://mikehadlow.blogspot.com/2011/05/easynetq-simple-net-api-for-rabbitmq.html
I've more or less gone through the same process as you. I've been
through a few iterations, and this is what I've settled on so far.
I have an IBus interface that is configured to send messages to a
topic exchange, and then I create multiple instances of that class
configured to multiple exchange (i.e. new Bus("host", "port",
"exchange")). The reason I do this is to de-emphasize exchanges and
emphasize routes to reduce the cognitive burden for the rest of our
team. The whole exchange/route model gives us more flexibility than
we need so I've simplified somewhat.
IBus looks like this:
variations of send:
void Send(params object[] messages)
void Send<TMessage>(params TMessage[] messages)
void Send(IEnumerable<object> messages)
void Send<TMessage>(IEnumerable<TMessage> messages)
a route method allowing explicit definition of the route:
void Route(string routeName, params object[] messages)
void Route(string routeName, IEnumerable<object> messages)
void Route<TMessage>(string routeName, params TMessage[] messages)
void Route<TMessage>(string routeName, IEnumerable<TMessage> messages)
async versions of all of the above:
void SendAsync<TMessage>(IEnumerable<TMessage> messages)
void RouteAsync<TMessage>(string routeName, params TMessage[] messages)
etc.
RPC requests:
object SendAndReceive(Type responseType, object request)
object SendAndReceive(Type responseType, object request, TimeSpan timeout)
TResponse SendAndReceive<TRequest, TResponse>(TRequest request)
TResponse SendAndReceive<TRequest, TResponse>(TRequest request,
TimeSpan timeout)
object RouteAndReceive(Type responseType, string routeName, object request)
object RouteAndReceive(Type responseType, string routeName, object
request, TimeSpan timeout)
TResponse RouteAndReceive<TRequest, TResponse>(string routeName,
TRequest request)
TResponse RouteAndReceive<TRequest, TResponse>(string routeName,
TRequest request, TimeSpan timeout)
IBus also has a RouteNameSelector property that references a class
with one method:
string SelectRouteName(BusConfig config, object message);
This can be swapped out for alternate implementations, but the default
does the following when calling Send methods (this is not used for the
Route methods):
1. if message implements IRoutable, return IRoutable.RouteName
2. if message has [RouteNameAttribute("RouteName")] return "RouteName"
3. otherwise return message.GetType().Name
subscriptions look like this:
var subscription = bus.Subscribe
.ToRoute("routeName")
.WithHandler(msg => { do something });
or
// where THandler : ConsumerOf<TMessage>
var subscription = bus.Subscribe
.ToQueue("queue name #1")
.ToQueue("queue name #2")
.WithContainerScopedHandler<TMessage, THandler>(container);
// equates for each message to:
// using (var childContainer = container.CreateLifeTimeContainer()) {
// var handler = container.Resolve<THandler>();
// handler.Consume(message);
// }
subscription.Start();
subscription.Stop();
There are, of course, many overloads that allow me to consume messages
in a variety of different ways (interface based, reflection method
based, delegate based, etc. with and without scoping to a container)
and additional fluent methods to control retries, timeouts, dead
letter handling, and the likes.
> Feedback would be much appreciated. I’m especially hoping that someone will
> look at the way I’m consuming messages. Currently with a simple while loop
> in a new thread:
>
> https://github.com/mikehadlow/EasyNetQ/blob/master/EasyNetQ/QueueingConsumerFactory.cs
>
>
>
> I’m sure there must be a better way.
We use QueueingBasicConsumer and are quite happy with it. I haven't
had a need to use anything else. Looking at our code, it's a little
different, but most of that just has to do error handling and the
additional code needed to support our abstractions.
Bryan
More information about the rabbitmq-discuss
mailing list