# Brighter – .NET Framework for building messaging app

If you need to .NET build an app that requires a queue/stream, Paramore. Brighter is an excellent option, it's based on enterprise integration patterns. It's very versatile, and it has a lot of useful packages like distributed lock and outbox patterns.

# Project

In this project I’ll show how to send and consume a message using Brighter with RabbitMQ, you will need a [podman](https://podman.io/) (to run RabbitMQ) and .NET 8 or 9

## Packages

For this project, it’s necessary to install these packages

* Paramore.Brighter.ServiceActivator - Allows you to consume messages
    
* Paramore.Brighter.ServiceActivator.Extensions.DependencyInjection - Useful method to register Brighter 
    
* Paramore.Brighter.ServiceActivator.Extensions.Hosting - Add support startup message consumer in the background
    
* Paramore.Brighter.MessagingGateway.RMQ - RabbitMQ package
    

## Messages

All messages in Brighter need to implement the `IRequest` interface.  
Brighter has a concept of `Event` & `Command` on the messages, where a command you have only one consumer and it allows to reply to the request and events are something that has already happened and can be handled by multiple consumers.

```csharp
public class Greeting(Guid id) : Event(id)
{
    public string Name { get; set; } = string.Empty;
}
```

## Handlers

Handlers are the consumer part of the app, where we can consume a message in an async or sync way.

```csharp
public class GreetingHandler : RequestHandler<Greeting>
{
    private readonly ILogger<GreetingHandler> _logger;

    public GreetingHandler(ILogger<GreetingHandler> logger)
    {
        _logger = logger;
    }

    public override Greeting Handle(Greeting command)
    {
        _logger.LogInformation("Hello {Name}", command.Name);
        return base.Handle(command);
    }
}
```

## Message mapper

On Brighter, we have a concept of Message (Header and Body) this decouple allows you to have multiple ways to serialize the messages, like for message A serialize using Json, for message B gRPC etc. Another advantage is it allows us to use one type internally before sending a map to another structure. For this project let's use a JSON serializer.

```csharp
public class GreetingMapper : IAmAMessageMapper<Greeting>
{
    public Message MapToMessage(Greeting request)
    {
        var header = new MessageHeader();
        header.Id = request.Id;
        header.TimeStamp = DateTime.UtcNow;
        header.Topic = "greeting.event";
        header.MessageType = MessageType.MT_EVENT;

        var body = new MessageBody(
            JsonSerializer.Serialize(request, JsonSerialisationOptions.Options)
        );

        return new Message(header, body);
    }

    public Greeting MapToRequest(Message message)
    {
        return JsonSerializer.Deserialize<Greeting>(message.Body.Bytes)!;
    }
}
```

## Register Brighter

For the next step, we need a `HostBuilder` where we are going to register `Brighter` using the `AddServiceActivator`, passing our subscription (message consumers).

```csharp
services.AddHostedService<ServiceActivatorHostedService>()
     .AddServiceActivator(opt => {});
```

Then we have 2 options, register everything manually

```csharp
services.AddHostedService<ServiceActivatorHostedService>()
     .AddServiceActivator(opt => {})
     .Handlers(register => register.Register<Greeting, GreetingHandler>())
     .MapperRegistry(register => register.Register<Greeting, GreetingMapper>());
```

or use the `AutoFromAssemblies`, so `Brighter` will scan all assemblies and register them

```csharp
services.AddHostedService<ServiceActivatorHostedService>()
     .AddServiceActivator(opt => {})
     .AutoFromAssemblies();
```

We need to setup the RabbitMQ connection and pass it to ChannelFactory & ProducerRegistryFactory.

```csharp
var rmqConnection = new RmqMessagingGatewayConnection
{
  AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
  Exchange = new Exchange("paramore.brighter.exchange"),
};
```

With this connection, we need to set a publication, for this project let's keep it simple by creating the queue if it does not exist (`MakeChannels = OnMissingChannel.Create`) and setting the queue name (with `Topic` property)

```csharp
var rmqConnection = new RmqMessagingGatewayConnection
{
  AmpqUri = new AmqpUriSpecification(new Uri("amqp://guest:guest@localhost:5672")),
  Exchange = new Exchange("paramore.brighter.exchange"),
};

services.AddServiceActivator(opt => {})
  .UseExternalBus(new RmqProducerRegistryFactory(rmqConnection,
     new RmqPublication[]
     {
        new()
        {
          MakeChannels = OnMissingChannel.Create,
          Topic = new RoutingKey("greeting.event"),
        },
      }
  ).Create());
```

The last part is setting up a consumer (queue subscription) and we configure it on `AddServiceActivator` by setting `Subscriptions` & `Channel` properties

```csharp
services.AddServiceActivator(opt =>
{
   opt.Subscriptions = new Subscription[]
   {
      new RmqSubscription<Greeting>(
        new SubscriptionName("paramore.example.greeting"),
        new ChannelName("greeting.event"),
        new RoutingKey("greeting.event"),
        makeChannels: OnMissingChannel.Create),
   };

   opt.ChannelFactory = new ChannelFactory(new RmqMessageConsumerFactory(rmqConnection));
});
```

## Publishing a message

Now we have everything set we can publish a message by

```csharp
var processor = host.Services.GetRequiredService<IAmACommandProcessor>();
processor.Post(new Greeting(Guid.NewGuid()) { Name = "hello"});
```

# Conclusion

Brighter is a nice framework, but it requires knowledge of enterprise integration patterns to understand the configuration of some Brighter design choices. I'm going to do more articles talking about enterprise integration patterns and Brighter.

# Reference

[https://brightercommand.gitbook.io/paramore-brighter-documentation](https://brightercommand.gitbook.io/paramore-brighter-documentation)

[https://github.com/lillo42/brighter-sample/tree/basic](https://github.com/lillo42/brighter-sample/tree/basic)
