Shuttle / Shuttle.Esb

A highly extensible service bus implementation.
http://shuttle.github.io/shuttle-esb/
BSD 3-Clause "New" or "Revised" License
95 stars 30 forks source link
msmq queue queueing rabbitmq service-bus

Documentation

Please visit out official documentation for more information.

Getting Started

Start a new Console Application project. We'll need to install one of the support queue implementations. For this example we'll use Shuttle.Esb.AzureStorageQueues which can be hosted locally using Azurite:

PM> Install-Package Shuttle.Esb.AzureStorageQueues

We'll also make use of the .NET generic host:

PM> Install-Package Microsoft.Extensions.Hosting

Next we'll implement our endpoint in order to start listening on our queue:

internal class Program
{
    static async Task Main(string[] args)
    {
        await Host.CreateDefaultBuilder()
            .ConfigureServices(services =>
            {
                services
                    .AddServiceBus(builder =>
                    {
                        builder.Options.Inbox.WorkQueueUri = "azuresq://azure/work";
                        builder.Options.Asynchronous = true; // NOTE: we'll be using async processing
                    })
                    .AddAzureStorageQueues(builder =>
                    {
                        builder.AddOptions("azure", new AzureStorageQueueOptions
                        {
                            ConnectionString = "UseDevelopmentStorage=true;"
                        });
                    });
            })
            .Build()
            .RunAsync();
    }
}

Even though the options may be set directly as above, typically one would make use of a configuration provider:

internal class Program
{
    private static async Task Main(string[] args)
    {
        await Host.CreateDefaultBuilder()
            .ConfigureServices(services =>
            {
                var configuration =
                    new ConfigurationBuilder()
                        .AddJsonFile("appsettings.json")
                        .Build();

                services
                    .AddSingleton<IConfiguration>(configuration)
                    .AddServiceBus(builder =>
                    {
                        configuration
                            .GetSection(ServiceBusOptions.SectionName)
                            .Bind(builder.Options);

                        builder.Options.Asynchronous = true; // NOTE: we'll be using async processing
                    })
                    .AddAzureStorageQueues(builder =>
                    {
                        builder.AddOptions("azure", new AzureStorageQueueOptions
                        {
                            ConnectionString = configuration
                                .GetConnectionString("azure")
                        });
                    });
            })
            .Build()
            .RunAsync();
    }
}

The appsettings.json file would be as follows (remember to set to Copy always):

{
  "ConnectionStrings": {
    "azure": "UseDevelopmentStorage=true;"
  },
  "Shuttle": {
    "ServiceBus": {
      "Inbox": {
        "WorkQueueUri": "azuresq://azure/work",
      }
    }
  }
}

Send a command message for processing

await serviceBus.SendAsync(new RegisterMember
{
    UserName = "user-name",
    EMailAddress = "user@domain.com"
});

Publish an event message when something interesting happens

Before publishing an event one would need to register an ISubscrtiptionService implementation such as Shuttle.Esb.Sql.Subscription.

await serviceBus.PublishAsync(new MemberRegistered
{
    UserName = "user-name"
});

Subscribe to those interesting events

services.AddServiceBus(builder =>
{
    builder.AddSubscription<MemberRegistered>();
});

Handle any messages

public class RegisterMemberHandler : IAsyncMessageHandler<RegisterMember>
{
    public RegisterMemberHandler(IDependency dependency)
    {
    }

    public async Task ProcessMessageAsync(IHandlerContext<RegisterMember> context)
    {
        // perform member registration

        await context.PublishAsync(new MemberRegistered
        {
            UserName = context.Message.UserName
        });
    }
}
public class MemberRegisteredHandler : IAsyncMessageHandler<MemberRegistered>
{
    public async Task ProcessMessageAsync(IHandlerContext<MemberRegistered> context)
    {
        // processing
    }
}