# Containers

MassTransit supports several popular dependency injection containers. However, MassTransit does not require a container, so don't just reach for one when getting started. If you are already using a container in your application, see if your container is supported and reference the appropriate NuGet package.

MassTransit has a consistent API for registration and configuration when used with a container, and also includes conventions for configuring receive endpoints for the registered consumers, sagas, and routing slip activities. Under the hood, each container is configured to properly interact with MassTransit, leveraging available container features, such as nested scopes for message consumers, without requiring the developer to explictly configure every consumer.

NOTE

Dependency Injection styles are a personal choice that each developer or organization must make on their own. We recognize this choice, and respect it, and will not judge those who don't use a particular container or style of dependency injection. In short, we care.

# Registration

MassTransit supports registration of consumers, sagas, and Courier activities for Autofac, Castle Windsor, Lamar, Microsoft Extensions Dependency Injection, Simple Injector, and StructureMap. When using one of these containers, the following registration methods should be used.

The .AddMassTransit extension method, which is specific to each container, supports both registration and bus configuration.

containerBuilder.AddMassTransit(r =>
{
    // register consumers, sagas, and Courier activities

    // register the bus in the container
    r.AddBus(context => Bus.Factory.CreateUsingInMemory(cfg =>
    {
        // configure receive endpoints, etc.
    }));
});

# Consumer Registration

To add a consumer registration, there are various methods available.

containerBuilder.AddMassTransit(r =>
{
    // add a consumer
    r.AddConsumer<UpdateCustomerAddressConsumer>();

    // add a consumer by type
    r.AddConsumer(typeof(UpdateCustomerAddressConsumer));

    // add a consumer by type, including a consumer definition for that consumer
    r.AddConsumer(typeof(UpdateCustomerAddressConsumer), typeof(UpdateCustomerAddressConsumerDefinition))

    // add all consumers in the specified assembly
    r.AddConsumers(Assembly.GetExecutingAssembly());

    // add multiple consumers and/or consumer definitions by type
    r.AddConsumers(typeof(ConsumerOne), typeof(ConsumerTwo));

    // adds ConsumerOne and its definition, and also adds ConsumerTwo
    r.AddConsumers(typeof(ConsumerOne), typeof(ConsumerOneDefinition), typeof(ConsumerTwo));

    // add consumers from the namespace containing the type
    r.AddConsumersFromNamespaceContaining<UpdateCustomerAddressConsumer>();
    r.AddConsumersFromNamespaceContaining(typeof(UpdateCustomerAddressConsumer));
});

To add a consumer registration and configure the consumer endpoint in the same expression, a definition can automatically be created.

containerBuilder.AddMassTransit(r =>
{
    r.AddConsumer<UpdateCustomerAddressConsumer>()
        .Endpoint(e =>
        {
            // customize the endpoint name
            e.Name = "customer-update";

            // specify the endpoint as temporary (may be non-durable, auto-delete, etc.)
            e.Temporary = false;

            // specify an optional concurrent message limit for the consumer
            e.ConcurrentMessageLimit = 8;

            // only use if needed, a sensible default is provided, and a reasonable
            // value is automatically calculated based upon ConcurrentMessageLimit if 
            // the transport supports it.
            e.PrefetchCount = 16;
        });
});

The endpoint configuration is available for all registration types, including consumers, sagas and Courier activities.

# Endpoint Configuration

When configuring the bus, using .AddBus, recieve endpoints can be explicitly configured, or configured using the registered consumers, sagas, and Courier activities along with an endpoint name formatter.

containerBuilder.AddMassTransit(r =>
{
    // register consumers, sagas, and Courier activities

    // register the bus in the container
    r.AddBus(context => Bus.Factory.CreateUsingInMemory(cfg =>
    {
        // configure endpoints for all registered consumer, saga, and Courier activities
        cfg.ConfigureEndpoints(context);
    }));
});

There are three endpoint name formatters included:

  • Default, which trims the Consumer, Saga, or Activity extension from the class name and uses it for the queue
  • SnakeCase, which trims and inserts an underscore before each uppercase letter
  • KababCase, which trims and inserts a hyphen before each uppercase letter

The default requires no additional configuration, whereas the other two can either be registered in the container or specified on the ConfigureEndpoints call.

containerBuilder.AddMassTransit(r =>
{
    r.AddBus(context => Bus.Factory.CreateUsingInMemory(cfg =>
    {
        cfg.ConfigureEndpoints(context, KebabCaseEndpointNameFormatter.Instance);
    }));
});

TODO: Add saga, activity

# Definition

In addition to registration, MassTransit supports an optional definition for the consumer, which can be specified (or discovered) via a class in the assembly. The syntax is under development, but some basic features are working today.

        public class SubmitOrderConsumerDefinition :
            ConsumerDefinition<SubmitOrderConsumer>
        {
            public SubmitOrderConsumerDefinition()
            {
                // override the default endpoint name, for whatever reason
                EndpointName = "ha-submit-order";

                // limit the number of messages consumed concurrently
                ConcurrentMessageLimit = 4;

                // this is under development, doesn't do anything yet!
                // but will eventually be used to define service endpoints
                // in conductor.
                Request<SubmitOrder>(x =>
                {
                    x.PartitionBy(m => m.CustomerId);

                    x.Publishes<OrderReceived>();
                    x.Responds<OrderAccepted>();
                    x.Responds<OrderRejected>();
                    x.Sends<ProcessOrder>();
                });
            }

            protected override void ConfigureConsumer(IReceiveEndpointConfigurator endpointConfigurator,
                IConsumerConfigurator<DiscoveryPingConsumer> consumerConfigurator)
            {
                endpointConfigurator.UseMessageRetry(r => r.Interval(5,1000));
                endpointConfigurator.UseInMemoryOutbox();
            }
        }

There are definitions for all consumer types, including sagas, activities, and saga state machines. They can be registered explicity using the .AddConsumer(consumer type, consumerDefinitionType) methods, or can be discovered using the scanning methods, such as .AddConsumersFromNamespaceContaining<SubmitOrderConsumer>().

Hey! Where is my container??

Containers come and go, so if you don't see your container here, or feel that the support for you container is weaksauce, pull requests are always welcome. Using an existing container it should be straight forward to add support for your favorite √úberContainer.