Skip to content

DependencyInjection

cgcel edited this page Jul 12, 2024 · 13 revisions

Catalog

Description

NanoRabbit is designed as a easy-to-register library.

Before Use

NanoRabbit is a Lightweight RabbitMQ .NET 3rd party library for .NET 6 and up, which is not including the management API of RabbitMQ, so you should deploy your own RabbitMQ and configure all the Users, Virtual Hosts, Exchanges, Queues before you start using NanoRabbit.

NanoRabbit DependencyInjection (Common Usage)

The only thing you need to do is inject NanoRabbit in Program.cs follow the below steps:

  1. Register RabbitHelper
  2. Add RabbitConsumer to RabbitHelper

RabbitHelper Injection

Inject RabbitHelper in Program.cs by calling AddRabbitHelper(this IServiceCollection services, Action\<RabbitConfigurationBuilder> builder), which is used to add a singleton service of the type specified in IRabbitHelper with a factory specified in implementationFactory to the specified Microsoft.Extensions.DependencyInjection.IServiceCollection.

var builder = Host.CreateApplicationBuilder(args);

builder.Services.AddRabbitHelper(builder =>
{
    builder.SetHostName("localhost")
        .SetPort(5672)
        .SetVirtualHost("/")
        .SetUserName("admin")
        .SetPassword("admin")
        .AddProducerOption(producer =>
        {
            producer.ProducerName = "FooProducer";
            producer.ExchangeName = "amq.topic";
            producer.RoutingKey = "foo.key";
            producer.Type = ExchangeType.Topic;
        })
        .AddConsumerOption(consumer =>
        {
            consumer.ConsumerName = "FooConsumer";
            consumer.QueueName = "foo-queue";
        });
})

Add RabbitConsumers

As the sample code above, we added a consumer option, so we have to add a RabbitConsumer to RabbitHelper to use the consumer option.

NanoRabbit provides a class named DefaultMessageHandler, which is a default implementation of IMessageHandler, you can simply inherit it and override the HandleMessage(string message) to handle the messages in queue.

Sample code:

public class FooQueueHandler : DefaultMessageHandler
{
    public override void HandleMessage(string message)
    {
        Console.WriteLine($"[x] Received from foo-queue: {message}");
        Task.Delay(1000).Wait();
        Console.WriteLine("[x] Done");
    }
}

Then we could add a RabbitConsumer to RabbitHelper:

builder.Services.AddRabbitHelper(builder =>
{
    builder.SetHostName("localhost")
        .SetPort(5672)
        .SetVirtualHost("/")
        .SetUserName("admin")
        .SetPassword("admin")
        .AddProducerOption(producer =>
        {
            producer.ProducerName = "FooProducer";
            producer.ExchangeName = "amq.topic";
            producer.RoutingKey = "foo.key";
            producer.Type = ExchangeType.Topic;
        })
        .AddConsumerOption(consumer =>
        {
            consumer.ConsumerName = "FooConsumer";
            consumer.QueueName = "foo-queue";
        });
})
.AddRabbitConsumer<FooQueueHandler>("FooConsumer", consumers: 1)

After that, build the host and run, and we can start to subscribe the queue.

using IHost host = builder.Build();
host.Run();

Use RabbitHelper

After injection, you can use RabbitHelper in the project, for example, create a BackgroundService, named "PublishService.cs":

public class PublishService : BackgroundService
{
    private readonly ILogger<PublishService> _logger;
    private readonly IRabbitHelper _rabbitHelper;

    public PublishService(ILogger<PublishService> logger, IRabbitHelper rabbitHelper)
    {
        _logger = logger;
        _rabbitHelper = rabbitHelper;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Testing PublishService");

        while (!stoppingToken.IsCancellationRequested)
        {
            _rabbitHelper.Publish("FooProducer", "Hello from FooProducer.");
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Then, add this BackgroundService at Program.cs:

builder.Services.AddHostedService<PublishService>();

NanoRabbit DependencyInjection (Adcanced)

There are some advenced usage of NanoRabbit:

  1. Add Keyed Singleton Service (For multiple connections)
  2. Add RabbitHelper by reading configs.

Add a Keyed Singleton RabbitHelper Service

In some cases, you want to inject more than one RabbitMQ connections in your project, which is possible by calling AddKeyedRabbitHelper(this IServiceCollection services, string key, Action<RabbitConfigurationBuilder> builders). This is a new feature, which is supported from .NET 7 on.

var builder = Host.CreateApplicationBuilder();

builder.Services.AddKeyedRabbitHelper("DefaultRabbitHelper", builder =>
{
    builder.SetHostName("localhost")
        .SetPort(5672)
        .SetVirtualHost("/")
        .SetUserName("admin")
        .SetPassword("admin")
        .AddProducerOption(producer =>
        {
            producer.ProducerName = "FooProducer";
            producer.ExchangeName = "amq.topic";
            producer.RoutingKey = "foo.key";
            producer.Type = ExchangeType.Topic;
        })
        .AddConsumerOption(consumer =>
        {
            consumer.ConsumerName = "DefaultFooConsumer";
            consumer.QueueName = "foo-queue";
        });
}).AddKeyedRabbitConsumer<DefaultMessageHandler>("DefaultRabbitHelper", "DefaultFooConsumer");

builder.Services.AddKeyedRabbitHelper("TestRabbitHelper", builder =>
{
    builder.SetHostName("localhost")
    .SetPort(5672)
    .SetVirtualHost("test")
    .SetUserName("admin")
    .SetPassword("admin")
    .AddProducerOption(producer =>
    {
        producer.ProducerName = "FooProducer";
        producer.ExchangeName = "amq.topic";
        producer.RoutingKey = "foo.key";
        producer.Type = ExchangeType.Topic;
    })
    .AddConsumerOption(consumer =>
    {
        consumer.ConsumerName = "TestFooConsumer";
        consumer.QueueName = "foo-queue";
    });
}).AddKeyedRabbitConsumer<DefaultMessageHandler>("TestRabbitHelper", "TestFooConsumer");

If you want to add RabbitConsumer to the Keyed RabbitHelper, you should use AddKeyedRabbitConsumer<THandler>(this IServiceCollection services, string key, string consumerName, int consumers = 1) function, with the same key configured in AddKeyedRabbitHelper.

How to get service

NanoRabbit provides a function (GetRabbitHelper(this IServiceProvider serviceProvider, string key)) to get RabbitHelper service by key, call it in your code:

public class DefaultPublishService : BackgroundService
{
    private readonly ILogger<DefaultPublishService> _logger;
    private readonly IRabbitHelper _rabbitHelper;

    public DefaultPublishService(ILogger<DefaultPublishService> logger, IServiceProvider serviceProvider)
    {
        _logger = logger;
        _rabbitHelper = serviceProvider.GetRabbitHelper("DefaultRabbitHelper");
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogInformation("Testing DefaultPublishService");

        while (!stoppingToken.IsCancellationRequested)
        {
            _rabbitHelper.Publish("FooProducer", "Hello from default publish service.");
            await Task.Delay(1000, stoppingToken);
        }
    }
}

Add RabbitHelper from appsettings.json

There is a way to add RabbitHelper with less code in Program.cs, write your configs of NanoRabbit in appsettings.json, and inject RabbitHelper by calling AddRabbitHelperFromAppSettings<TRabbitConfiguration>(this IServiceCollection services, IConfiguration configuration).

Default usage

According to RabbitConfiguration predefined in NanoRabbit, we should add the config with the same format in appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "RabbitConfiguration": {
    "HostName": "localhost",
    "Port": 5672,
    "UserName": "admin",
    "Password": "admin",
    "VirtualHost": "/",

    "Producers": [
      {
        "ProducerName": "FooProducer",
        "ExchangeName": "amq.topic",
        "RoutingKey": "foo.key",
        "Type": "topic"
      },
      {
        "ProducerName": "BarProducer",
        "ExchangeName": "amq.direct",
        "RoutingKey": "bar.key",
        "Type": "direct"
      }
    ],
    "Consumers": [
      {
        "ConsumerName": "FooConsumer",
        "QueueName": "foo-queue"
      },
      {
        "ConsumerName": "BarConsumer",
        "QueueName": "bar-queue"
      }
    ]
  }
}

Add RabbitHelper in Program.cs:

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddRabbitHelperFromAppSettings<FooConfiguration>(builder.Configuration)
    .AddRabbitConsumer<FooQueueHandler>("FooConsumer")
    .AddRabbitConsumer<BarQueueHandler>("BarConsumer");

Multiple Connections

You can register multiple connections by using new feature (AddKeyedSingleton), which is added from .NET 7 on.

Define your own class that inherited RabbitConfiguration, for example:

public class FooConfiguration : RabbitConfiguration { }
public class BarConfiguration : RabbitConfiguration { }

Add the configs of RabbitMQ connections in appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  },
  "FooConfiguration": {
    "HostName": "localhost",
    "Port": 5672,
    "UserName": "admin",
    "Password": "admin",
    "VirtualHost": "/",
  },
  "BarConfiguration": {
    "HostName": "localhost",
    "Port": 5672,
    "UserName": "admin",
    "Password": "admin",
    "VirtualHost": "/",
  }
}

Add RabbitHelper in Program.cs:

var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddKeyedRabbitHelperFromAppSettings<FooConfiguration>("FooConnection", builder.Configuration);
builder.Services.AddKeyedRabbitHelperFromAppSettings<BarConfiguration>("BarConnection", builder.Configuration);

To use your specified RabbitHelper, See here.