Registering a generic decorator of a Consumer using Autofac

912 views
Skip to first unread message

Quooston

unread,
Sep 3, 2012, 1:17:36 AM9/3/12
to masstrans...@googlegroups.com
Hi,

I'd like to know how I could register a command handler which decorates another, in such a way to remain true to the pattern and that MT accepts it.

For example, if I have a LoggingCommandHandler, how would I register it (with Autofac) such that MassTransit resolves the decorated instance instead of the original instance?

The decorator would look something like this: 

public LoggingCommandHandler<T> : Consumes<T>.All where T : class
{
    private Consumes<T>.All _decorated;

    public  LoggingCommandHandler(Consumes<T>.All decorated)
    {
        _decorated = decorated;
    }

    public void Consume(T command)
    {
        //Log start
        
        _decorated.Consume(command);

        //Log end
    }  
}



Is it possible to register open generic types using Autofac for MT? At the moment it looks like that is not the case.

Or should I just be going about this some other way?

TIA,
Q


Chris Patterson

unread,
Sep 3, 2012, 12:23:16 PM9/3/12
to masstrans...@googlegroups.com
You probably want to start decorating at the IConsumerFactory<TConsumer> level. That way, you can create an extension method for your own decorator that you can use in the subscription of your consumer. If you look at how .Consumer<T>() works in the SubscriptionBusServiceConfigurator now, you can see how the extension method maps the various overloads to the proper consumer factory.

If you want to decorate it, just create your own IConsumerFactory<>, which can then call the MT one underneath if you like so you don't have to deal with the context dispatching and such.



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

Quooston

unread,
Sep 3, 2012, 7:56:54 PM9/3/12
to masstrans...@googlegroups.com
Thanks for that Chris, I'll look into it. 

Mick Delaney

unread,
Oct 17, 2014, 12:29:22 PM10/17/14
to masstrans...@googlegroups.com
i know this is an old thread but:

I've created my own custom IConsumerFactory<T> which loads consumers out of windsor. 

but i'm struggling to see how I can create a series of decorators around my IConsumerFactory implementations. 

is there some code sample somewhere to show me. 

i've looked at IOutboundMessageInterceptor but what I want is something like this:


  public class WindsorScopedConsumerFactory<T> : IConsumerFactory<T> where T : class
   
{
       
readonly IConsumerFactory<T> _next;
       
readonly IWindsorContainer _container;


       
public WindsorScopedConsumerFactory(IConsumerFactory<T> next, IWindsorContainer container)
       
{
            _next
= next;
            _container
= container;
       
}


       
public IEnumerable<Action<IConsumeContext<TMessage>>> GetConsumer<TMessage>(IConsumeContext<TMessage> context,
                 
InstanceHandlerSelector<T, TMessage> selector) where TMessage : class
       
{
           
           
using (_container.BeginScope())
           
{
               
return _next.GetConsumer(context, selector);
           
}
       
}
   
}


which would decorate the final ConsumerFactory:

   
public class WindsorConsumerFactory<T> : IConsumerFactory<T> where T : class
   
{
       
readonly IWindsorContainer _container;


       
public WindsorConsumerFactory(IWindsorContainer container)
       
{
            _container
= container;
       
}


       
public IEnumerable<Action<IConsumeContext<TMessage>>> GetConsumer<TMessage>(IConsumeContext<TMessage> context, InstanceHandlerSelector<T, TMessage> selector) where TMessage : class
       
{
            T consumer
= null;


           
try
           
{
                consumer
= _container.Resolve<T>();


               
if (consumer == null)
               
{
                   
throw new ConfigurationException(string.Format("Unable to resolve type '{0}' from container: ", typeof(T)));
               
}


               
foreach (var handler in selector(consumer, context))
               
{
                   
yield return handler;
               
}
           
}
           
finally
           
{
                _container
.Release(consumer);
           
}
           
       
}
   
}






i'm i going down the correct path ???




On Monday, 3 September 2012 17:23:17 UTC+1, Chris Patterson wrote:
You probably want to start decorating at the IConsumerFactory<TConsumer> level. That way, you can create an extension method for your own decorator that you can use in the subscription of your consumer. If you look at how .Consumer<T>() works in the SubscriptionBusServiceConfigurator now, you can see how the extension method maps the various overloads to the proper consumer factory.

If you want to decorate it, just create your own IConsumerFactory<>, which can then call the MT one underneath if you like so you don't have to deal with the context dispatching and such.

On Mon, Sep 3, 2012 at 12:17 AM, Quooston <qer...@gmail.com> wrote:
Hi,

I'd like to know how I could register a command handler which decorates another, in such a way to remain true to the pattern and that MT accepts it.

For example, if I have a LoggingCommandHandler, how would I register it (with Autofac) such that MassTransit resolves the decorated instance instead of the original instance?

The decorator would look something like this: 

public LoggingCommandHandler<T> : Consumes<T>.All where T : class
{
    private Consumes<T>.All _decorated;

    public  LoggingCommandHandler(Consumes<T>.All decorated)
    {
        _decorated = decorated;
    }

    public void Consume(T command)
    {
        //Log start
        
        _decorated.Consume(command);

        //Log end
    }  
}



Is it possible to register open generic types using Autofac for MT? At the moment it looks like that is not the case.

Or should I just be going about this some other way?

TIA,
Q


--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To post to this group, send email to masstrans...@googlegroups.com.
To unsubscribe from this group, send email to masstransit-discuss+unsub...@googlegroups.com.

Chris Patterson

unread,
Oct 17, 2014, 12:43:16 PM10/17/14
to masstrans...@googlegroups.com
On Fri, Oct 17, 2014 at 9:29 AM, Mick Delaney <mickd...@gmail.com> wrote:
foreach (var handler in selector(consumer, context))
               
{
                   
yield return handler;
               
}

You are on the right path, you just need to add the intercepting code around handler in this section of your factory.

Something like:

yield return x => {
    // do something with x, etc.
    handler(x);
    // do something with x after consumer done
};

You're decorating the action of handler, which is actually called to consume the message.

Mick Delaney

unread,
Oct 17, 2014, 1:55:32 PM10/17/14
to masstrans...@googlegroups.com
Something like this:


 
public class LoggingDecorator<T> : IConsumerFactory<T> where T : class
   
{
       
readonly ILog _logger = LogManager.GetLogger(typeof(LoggingDecorator<T>));


       
readonly IConsumerFactory<T> _next;


       
public LoggingDecorator(IConsumerFactory<T> next)
       
{
            _next
= next;

       
}


       
public IEnumerable<Action<IConsumeContext<TMessage>>> GetConsumer<TMessage>(IConsumeContext<TMessage> context,
                 
InstanceHandlerSelector<T, TMessage> selector) where TMessage : class
       
{

           
IEnumerable<Action<IConsumeContext<TMessage>>> consumers = _next.GetConsumer(context, selector);


           
foreach (var action in consumers)
           
{
               
Action<IConsumeContext<TMessage>> consumer = action;


               
yield return message =>
               
{
                   
try
                   
{
                        consumer
(message);
                   
}
                   
catch (Exception e)
                   
{
                        _logger
.Error(e);
                   
}
               
};
           
}
       
}
   
}

Chris Patterson

unread,
Oct 17, 2014, 2:28:08 PM10/17/14
to masstrans...@googlegroups.com
That looks right to me!


--
You received this message because you are subscribed to the Google Groups "masstransit-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to masstransit-dis...@googlegroups.com.

To post to this group, send email to masstrans...@googlegroups.com.

mick delaney

unread,
Oct 17, 2014, 3:11:55 PM10/17/14
to masstrans...@googlegroups.com
Thanks for your help Chris, much appreciated. 

Sent from my iPad
You received this message because you are subscribed to a topic in the Google Groups "masstransit-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/masstransit-discuss/q5Sz3Cy6zS0/unsubscribe.
To unsubscribe from this group and all its topics, send an email to masstransit-dis...@googlegroups.com.

To post to this group, send email to masstrans...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages