This repository offers a wide collection of .NET packages for use in microservices architecture.
- RabbitMQ Consumer
- Logging
- API Middlewares
- API Documentation
- Domain Events
- Integration Events
- Kubernetes Insights
- Kubernetes Health Checks
- NHibernate
- Notifications
- Notifications Audit
To use the RabbitMQ consumer, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.RabbitMq.Consumer
then you can choose one of three ways to add the consumer:
- with event marked by attribute
- with manual listed events (builder)
- Old way, implement IRabbitMqMessageProcessor
!IMPORTANT:
RoutingKeys
section inRabbitMqConsumerSettings
(config) should be empty (removed), because it fills that section automatically (and throw error if config has some data)
this way requires implementing IRabbitMqEventProcessor<TEvent>
interface, where TEvent
- base type of messages
public interface IRabbitMqEventProcessor<in TEvent>
{
Task ProcessAsync(TEvent @event, CancellationToken token);
}
and then add:
services
.AddPlatformRabbitMqClient(configuration)
.AddPlatformRabbitMqConsumerWithMessages<RabbitMqEventProcessorImplementation, IRequest, RabbitEventAttribute>(
configuration,
x => x.RoutingKey);
where
public class RabbitEventAttribute(string routingKey) : Attribute
{
public string RoutingKey { get; } = routingKey;
}
[RabbitEvent("RoutingKey1")]
public record MessageOne(string Name, Guid Id): IRequest;
This method will find all types that has attribute RabbitEvent
in the attribute's assembly and try to add them to
consumer for handling corresponded routing key.
If type is not implement / inherit type
IRequest
(second generic argument ofAddPlatformRabbitMqConsumerWithMessages
) - will throw exception (on startup)
!IMPORTANT:
RoutingKeys
section inRabbitMqConsumerSettings
(config) should be empty (removed), because it fills that section automatically (and throw error if config has some data)
this way requires implementing IRabbitMqEventProcessor<TEvent>
interface, where TEvent
- base type of messages
public interface IRabbitMqEventProcessor<in TEvent>
{
Task ProcessAsync(TEvent @event, CancellationToken token);
}
and then add:
services
.AddPlatformRabbitMqClient(configuration)
.AddPlatformRabbitMqConsumerWithMessages<RabbitMqEventProcessorImplementation, IRequest>(
configuration,
x => x
.Add<MessageOne>("RoutingKey1")
.Add<MessageTwo>("RoutingKey2"));
This way allows to explicitly add all required messages with routing keys to consumer.
You need implement interface IRabbitMqMessageProcessor
public class MessageProcessor : IRabbitMqMessageProcessor
{
public Task ProcessAsync(IBasicProperties properties, string routingKey, string message, CancellationToken token)
{
// write your consuming logic here
}
}
Finally, register the RabbitMQ consumer in DI
services
.AddPlatformRabbitMqClient(configuration)
.AddPlatformRabbitMqConsumer<MessageProcessor>(configuration);
!IMPORTANT:
RoutingKeys
section inRabbitMqConsumerSettings
(config) should contain all routing keys that you want to consume and it will be added to queue's bindings (ifRoutingKeys
is empty - adds#
binding)
!IMPORTANT: If you run more than one consumer, they will consume messages in parallel mode. In order to change it follow the instructions below.
Switch consuming mode in appsettings.json file
{
"RabbitMQ": {
"Consumer": {
"Mode": "SingleActiveConsumer"
}
}
}
Register the consumer lock service in DI
services
.AddPlatformRabbitMqSqlServerConsumerLock(configuration.GetConnectionString("ms sql connection string"));
To use platform logger, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Logging
In the second step, you need register the logger in DI
builder.Host.AddPlatformLogging();
Finally, register sinks in appsettings.json file
{
"Serilog": {
"MinimumLevel": {
"Default": "Information",
"Override": {
"System": "Error",
"Microsoft": "Error",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"WriteTo": [
{
"Name": "Console",
"Args": {
"formatter": "Serilog.Formatting.Compact.RenderedCompactJsonFormatter, Serilog.Formatting.Compact"
}
}
]
}
}
To use platform API middlewares, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Api.Middlewares
To log exceptions you need to use errors middleware.
app.UsePlatformErrorsMiddleware(); // This middleware should be the first
Important
If you need to change response status code, then you should register status code resolver.
services.AddSingleton<IStatusCodeResolver, YourStatusCodeResolver>();
To use platform API documentation, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Api.Documentation
Finally, you need register it in DI
services
.AddPlatformApiDocumentation(builder.Environment);
app
.UsePlatformApiDocumentation(builder.Environment);
To use events, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Events
To use domain events, you need register it in DI
services
.AddPlatformDomainEvents();
Now, you can publish it in this way
public class CommandHandler(IDomainEventPublisher eventPublisher) : IRequestHandler<Command>
{
public async Task Handle(Command request, CancellationToken cancellationToken)
{
await eventPublisher.PublishAsync(new DomainEvent(), cancellationToken);
}
}
And process it in this way
public class EventHandler : INotificationHandler<DomainEvent>
{
public async Task Handle(DomainEvent notification, CancellationToken cancellationToken)
{
// your logic
}
}
In the first step, you need implement interface IIntegrationEventProcessor
public class IntegrationEventProcessor : IIntegrationEventProcessor
{
public Task ProcessAsync(IIntegrationEvent @event, CancellationToken cancellationToken)
{
// write your consuming logic here
}
}
Then, register integration events in DI
services
.AddPlatformIntegrationEvents<IntegrationEventProcessor>(
typeof(IntegrationEvents).Assembly,
x =>
{
x.SqlServer.ConnectionString = "ms sql connection string";
x.MessageQueue.ExchangeName = "integration.events";
x.MessageQueue.Host = "RabbitMQ host";
x.MessageQueue.Port = "RabbitMQ port";
x.MessageQueue.VirtualHost = "RabbitMQ virtual host";
x.MessageQueue.UserName = "RabbitMQ username";
x.MessageQueue.Secret = "RabbitMQ secret";
});
Now, you can publish it in this way
public class CommandHandler(IIntegrationEventPublisher eventPublisher) : IRequestHandler<Command>
{
public async Task Handle(Command request, CancellationToken cancellationToken)
{
await eventPublisher.PublishAsync(new IntegrationEvent(), cancellationToken);
}
}
And process it in this way
public class EventHandler : INotificationHandler<IntegrationEvent>
{
public async Task Handle(IntegrationEvent notification, CancellationToken cancellationToken)
{
// your logic
}
}
Options
Option | Description | Type | Default value |
---|---|---|---|
DashboardPath | Dashboard relative path | string | /admin/events |
FailedRetryCount | The number of message retries | int | 5 |
RetentionDays | Success message live period | int | 15 |
SqlServer.Schema | Shema name for event tables | string | events |
MessageQueue.Enable | For developer purpose only. If false, then switches RabbitMQ queue to queue in memory | string | true |
To use kubernetes utils, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Kubernetes
To enable application insights, just register it in DI
services
.AddPlatformKubernetesInsights(
builder.Configuration,
opt =>
{
opt.SkipSuccessfulDependency = true;
opt.RoleName = Environment.GetEnvironmentVariable("APP_NAME");
opt.AdditionalHealthCheckPathToSkip = ["/DoHealthCheck"];
});
All settings have default values and optional (as well as opt
argument in AddPlatformKubernetesInsights
):
Option | Description | Type | Default value |
---|---|---|---|
SkipSuccessfulDependency | Skip dependency without error | bool | false |
SkipDefaultHealthChecks | Skip requests to default health checks (/health/ready ,/health/live ) |
bool | true |
AdditionalHealthCheckPathToSkip | Additional paths to skip their requests as healthchecks | string[] | [] |
SetAuthenticatedUserFromHttpContext | Fill AuthenticatedUserId from HttpContext.User.Identity.Name | bool | true |
RoleName | Value to set as role name for AppInsight requests | string | <assembly name> |
To add health checks for your service, you need register it in DI
services
.AddPlatformKubernetesHealthChecks("your db connection string");
app
.UsePlatformKubernetesHealthChecks();
After that, health checks will be available by URLs
- /health/live
- /health/ready
To use the IQueryable mock, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.NHibernate.UnitTesting
To mock IQueryable, in your code, call:
var entity = new Entity();
repository.GetQueryable().Returns(new TestQueryable<Entity>(entity));
To use platform senders for notifications, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Notifications
Then register notifications service in DI
services
.AddPlatformNotifications(builder.Environment, builder.Configuration)
Then fill configuration settings:
{
"NotificationSender": {
"Server": "smtp.server.com", // smtp server host
"RedirectTo": ["[email protected]"], // all messages on non-prod environments will be sent to these addresses, recipients will be listed in message body
"DefaultRecipients": ["[email protected]"] // if no recipients are provided for a message then these emails will become recipients
}
}
Now you can send messages to smtp server:
public class YourNotificationRequestHandler(IEmailSender sender) : IRequestHandler<YourNotificationRequest>
{
public async Task Handle(YourNotificationRequest request, CancellationToken cancellationToken)
{
var attachment = new Attachment(new MemoryStream(), request.AttachmentName);
attachment.ContentDisposition!.Inline = true;
var message = new EmailModel(
request.Subject,
request.Body,
new MailAddress(request.From),
new[] { new MailAddress(request.To) },
Attachments: new[] { attachment });
await sender.SendAsync(message, token);
}
}
Note
Attachment will be added to notification only if:
- it is not inlined
- it is inlined and referred by name as image source in notification text
To audit sent notifications, first install the NuGet package:
dotnet add package Luxoft.Bss.Platform.Notifications.Audit
Then register notifications service in DI with provided sql connection
services
.AddPlatformNotificationsAudit(o => o.ConnectionString = builder.Configuration.GetConnectionString("DefaultConnection")!);
Thats all - db schema and tables will be generated on application start (you can customize schema and table names on DI step).