Skip to content

Support fluent configuration as well as attibutes #4

Closed

Description

@iancooper

The fluent configuration needs to work with SubscriberRegistry and register the first item in the chain. In order to support fluent and attributes we might to parse all handlers in the chain for attributes and insert into the chain where there are attributes even if using fluent.


Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

Activity

  1. self-assigned this
    on Sep 24, 2014
  2. removed their assignment
    on Feb 12, 2015
  3. edblackburn commented on Apr 14, 2016

    @edblackburn

    Do you have anything specific in mind in terms of features or style? I find writing attributes just to dictate order grating, especially as I perceive I've already configured my pipeline elsewhere.

    Examples could be:

    var registry = new SubscriberRegistry();
    
    registry.RegisterAsync<IngestSecurity, IngestSecurityHandler>()
        .With
        .Handler<XHandler>()
        .Handler<YHandler>()
        .Handler<ZHandler>();

    Which maintains backward compatibility. In addendum you could also have:

    var registry = new SubscriberRegistry();
    
    registry.RegisterAsync<IngestSecurity>()
        .With
        .Handler<XHandler>()
        .Handler<YHandler>()
        .Handler<ZHandler>()
        .Handler<IngestSecurityHandler>();

    Obviously RegisterAsync and Register would spawn specific config, with appropriate generic constraints to prevent mixing them up.

    .Handler could also take Handler(typeof(XHandler));

    The chain could be composing HandlersDescriptors under the hood so could be extended with extension methods. As suggested above it would probably make sense to create items in the config model to represent attributes too.

    I think it'd be beneficial to include a Verify() member for the pipeline builder (or unit tests) internally to double check conflicts, particularly between registration config and attribute config?

    I can only see what is useful for my own purposes so am happy to defer to something / someone more appropriate.

    Thoughts?

  4. ianbattersby commented on Apr 14, 2016

    @ianbattersby
    Contributor

    We've built something internally similar to this, I think it's good move to have a builder which can provide instantiations of the many interfaces Brighter requires for command professor and dispatcher.

  5. iancooper commented on Apr 14, 2016

    @iancooper
    MemberAuthor

    I didn't have anything specific in mind. At the point I wrote this it was enough that it be compatible as an idea, as I was going with attributes and desired to leave implementation to someone who wanted fluent.

    One internal request is default filters in the pipeline i.e. Give everything a logging step.

    One way would be to add this to CP builder buyout would be nice to fold that request into this space.

  6. edblackburn commented on Apr 14, 2016

    @edblackburn

    @ianbattersby Anything you can share? I don't fancy reinventing the wheel?

    @iancooper I should be in London Tuesday afternoon if you or @ianbattersby are about we can discuss in person.

    I have to complete some features first. As soon as that's done I can take a proper look (or not depending on what maybe already available).

  7. ianbattersby commented on May 13, 2016

    @ianbattersby
    Contributor

    @edblackburn Ed I'm really sorry, I completely forgot to reply!

    Here you go with our simple 'make do' effort although our feeling is to get beyond this we'd need to make breaking changes to the existing fluency;

    using System;
    
        using paramore.brighter.commandprocessor;
    
        using StructureMap;
    
        public class BrighterConfigurationBuilder
        {
            private readonly MessageMapperFactory messageMapperFactory;
            private readonly HandlerFactory handlerFactory;
            private readonly MessageMapperRegistry messageMapperRegistry;
            private readonly SubscriberRegistry handlerRegistry;
    
            public BrighterConfigurationBuilder(IContainer container)
            {
                this.messageMapperFactory = new MessageMapperFactory(container);
                this.messageMapperRegistry = new MessageMapperRegistry(this.messageMapperFactory);
                this.handlerFactory = new HandlerFactory(container);
                this.handlerRegistry = new SubscriberRegistry();
            }
    
            public BrighterConfigurationBuilder Register<TRequest, THandler, TMapper>()
                where TRequest : class, IRequest
                where TMapper : class, IAmAMessageMapper<TRequest>
                where THandler : class, IHandleRequests<TRequest>
            {
                this.messageMapperFactory.Register<TRequest, TMapper>();
                this.messageMapperRegistry.Register<TRequest, TMapper>();
                this.handlerFactory.Register<TRequest, THandler>();
                this.handlerRegistry.Register<TRequest, THandler>();
    
                return this;
            }
    
            public BrighterConfigurationBuilder Register(Type type, Type handler, Type mapper)
            {
                this.messageMapperFactory.Register(type, mapper);
                this.messageMapperRegistry.Add(type, mapper);
                this.handlerFactory.Register(type, handler);
                this.handlerRegistry.Add(type, handler);
    
                return this;
            }
    
            public BrighterConfigurationBuilder Register<TRequest, TMapper>()
                where TRequest : class, IRequest
                where TMapper : class, IAmAMessageMapper<TRequest>
            {
                this.messageMapperFactory.Register<TRequest, TMapper>();
                this.messageMapperRegistry.Register<TRequest, TMapper>();
    
                return this;
            }
    
            public IBrighterConfiguration Build()
            {
                return new BrighterConfiguration(this.handlerFactory, this.messageMapperFactory, this.handlerRegistry, this.messageMapperRegistry);
            }
        }
    
        public class BrighterConfiguration : IBrighterConfiguration
        {
            private readonly MessageMapperFactory messageMapperFactory;
    
            private readonly HandlerFactory handlerFactory;
    
            private readonly MessageMapperRegistry messageMapperRegistry;
    
            private readonly SubscriberRegistry subscriberRegistry;
    
            public BrighterConfiguration(HandlerFactory handlerFactory, MessageMapperFactory messageMapperFactory, SubscriberRegistry handlerRegistry, MessageMapperRegistry messageMapperRegistry)
            {
                this.messageMapperFactory = messageMapperFactory;
                this.handlerFactory = handlerFactory;
                this.subscriberRegistry = handlerRegistry;
                this.messageMapperRegistry = messageMapperRegistry;
            }
    
            public IAmAHandlerFactory HandlerFactory => this.handlerFactory;
    
            public IAmAMessageMapperFactory MessageMapperFactory => this.messageMapperFactory;
    
            public IAmASubscriberRegistry HandlerRegistry => this.subscriberRegistry;
    
            public IAmAMessageMapperRegistry MessageMapperRegistry => this.messageMapperRegistry;
    
            public HandlerConfiguration HandlerConfiguration => new HandlerConfiguration(this.HandlerRegistry, this.handlerFactory);
        }
    

    ... and we use it like this;

                var logger = LogProvider.GetLogger(BrighterLoggerName);
    
                var brighterConfiguration = new BrighterConfigurationBuilder(this.container)
                    .Register<SomeCommand, SomeCommandHandler, GenericCommandMessageMapper<SomeCommand>>()
                    .Register<SomeOtherCommand, GenericCommandMessageMapper<SomeOtherCommand>>()
                    .Build();
    
                this.dispatcher = DispatchBuilder.With()
                    .CommandProcessor(CommandProcessorBuilder.With()
                        .Handlers(brighterConfiguration.HandlerConfiguration)
                        .Policies(ApplicationPolicyRegistry.Create())
                        .TaskQueues(new MessagingConfiguration(new MessageStoreSink(), new RmqMessageProducer(logger), brighterConfiguration.MessageMapperRegistry))
                        .RequestContextFactory(new InMemoryRequestContextFactory())
                        .Build())
                    .MessageMappers(brighterConfiguration.MessageMapperRegistry)
                    .ChannelFactory(new InputChannelFactory(new RmqMessageConsumerFactory(logger), new RmqMessageProducerFactory(logger)))
                    .ConnectionsFromConfiguration()
                    .Build();
    
                this.container.Configure(
                    c =>
                        {
                            c.For<IAmACommandProcessor>().Use(this.dispatcher.CommandProcessor);
                            c.For(typeof(LoggingContextHandler<>)).Use(typeof(LoggingContextHandler<>));
                        });
    
                this.dispatcher.Receive();
    
  8. edblackburn commented on Jun 29, 2016

    @edblackburn

    @ianbattersby No worries. Am at a different gig now, may return to this if it becomes a problem again. Incidentally I found this again whilst googling for Brighter and structure map config.

  9. 47 remaining items

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions