Skip to content

Commit

Permalink
Messaging MultiTenancy Exception handling (#242)
Browse files Browse the repository at this point in the history
Co-authored-by: Radu Popovici <rpopovici@totalsoft.ro>
  • Loading branch information
oncicaradupopovici and Radu Popovici authored Nov 10, 2022
1 parent cb61052 commit 6bcd832
Show file tree
Hide file tree
Showing 20 changed files with 281 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
// This source code is licensed under the MIT license.

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using NBB.Messaging.Abstractions;
using NBB.Todo.Data;
using NBB.Todo.Data.Entities;
using NBB.Todo.PublishedLanguage;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
Expand All @@ -27,8 +29,9 @@ public TodoController(TodoDbContext todoDbContext, IMessageBus messageBus)
}

[HttpGet]
public IEnumerable<TodoTask> Get()
=> _todoDbContext.TodoTasks.ToList();
public Task<List<TodoTask>> Get()
=> _todoDbContext.TodoTasks.ToListAsync();
//=> throw new Exception("Test exeception");

[HttpPost]
public async Task Post([FromBody]CreateTodoTask command, CancellationToken cancellationToken)
Expand Down
5 changes: 5 additions & 0 deletions samples/MultiTenancy/NBB.Todo.Api/NBB.Todo.Api.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,21 @@
<PackageReference Include="Serilog.AspNetCore" Version="$(SerilogAspNetCorePackageVersion)" />
<PackageReference Include="Serilog.Extensions.Logging" Version="$(SerilogExtensionsLoggingPackageVersion)" />
<PackageReference Include="Serilog.Sinks.Console" Version="$(SerilogSinksConsole)" />
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="$(SerilogSinksMSSqlServerPackageVersion)" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="Hellang.Middleware.ProblemDetails" Version="6.3.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Correlation\NBB.Correlation.AspNet\NBB.Correlation.AspNet.csproj" />
<ProjectReference Include="..\..\..\src\Correlation\NBB.Correlation.Serilog\NBB.Correlation.Serilog.csproj" />
<ProjectReference Include="..\..\..\src\EventStore\NBB.EventStore.AdoNet.Multitenancy\NBB.EventStore.AdoNet.MultiTenancy.csproj" />
<ProjectReference Include="..\..\..\src\Messaging\NBB.Messaging.Abstractions\NBB.Messaging.Abstractions.csproj" />
<ProjectReference Include="..\..\..\src\Messaging\NBB.Messaging.MultiTenancy\NBB.Messaging.MultiTenancy.csproj" />
<ProjectReference Include="..\..\..\src\Messaging\NBB.Messaging.Nats\NBB.Messaging.Nats.csproj" />
<ProjectReference Include="..\..\..\src\MultiTenancy\NBB.MultiTenancy.AspNet\NBB.MultiTenancy.AspNet.csproj" />
<ProjectReference Include="..\..\..\src\MultiTenancy\NBB.MultiTenancy.Identification.Http\NBB.MultiTenancy.Identification.Http.csproj" />
<ProjectReference Include="..\..\..\src\Tools\Serilog\NBB.Tools.Serilog.Enrichers.TenantId\NBB.Tools.Serilog.Enrichers.TenantId.csproj" />
<ProjectReference Include="..\NBB.Todo.Data\NBB.Todo.Data.csproj" />
<ProjectReference Include="..\NBB.Todo.PublishedLanguage\NBB.Todo.PublishedLanguage.csproj" />
</ItemGroup>
Expand Down
26 changes: 12 additions & 14 deletions samples/MultiTenancy/NBB.Todo.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Serilog;
using Serilog.Events;
using NBB.Correlation.Serilog;
using Microsoft.Extensions.DependencyInjection;
using NBB.Tools.Serilog.Enrichers.TenantId;

namespace NBB.Todo.Api
{
Expand All @@ -21,21 +22,18 @@ public static void Main(string[] args)

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseSerilog()
.ConfigureLogging(ConfigureLogging)
.UseSerilog((context, services, logConfig) =>
{
logConfig
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.Enrich.With<CorrelationLogEventEnricher>()
.Enrich.With(services.GetRequiredService<TenantEnricher>());
logConfig.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}");
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});

private static void ConfigureLogging(HostBuilderContext ctx, ILoggingBuilder _builder)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(ctx.Configuration)
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
}
}
}
57 changes: 55 additions & 2 deletions samples/MultiTenancy/NBB.Todo.Api/Startup.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
// Copyright (c) TotalSoft.
// This source code is licensed under the MIT license.

using Hellang.Middleware.ProblemDetails;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using NBB.Correlation;
using NBB.Correlation.AspNet;
using NBB.MultiTenancy.Abstractions.Repositories;
using NBB.MultiTenancy.AspNet;
using NBB.Todos.Data;

using NBB.Tools.Serilog.Enrichers.TenantId;
using System;

namespace NBB.Todo.Api
{
Expand All @@ -32,12 +37,22 @@ public void ConfigureServices(IServiceCollection services)
services.AddTodoDataAccess();

services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSwaggerGen(options => options.OperationFilter<SwaggerTenantHeaderFilter>());
services.AddSwaggerGen(options =>
{
if (Configuration.IsMultiTenant())
{
options.OperationFilter<SwaggerTenantHeaderFilter>();
}
});

services.AddMultitenancy(Configuration)
.AddDefaultHttpTenantIdentification()
.AddMultiTenantMessaging()
.AddTenantRepository<ConfigurationTenantRepository>();
services.AddSingleton<TenantEnricher>();

services.AddProblemDetails(config => ConfigureProblemDetails(config));

}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
Expand All @@ -54,12 +69,50 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseSwagger();
app.UseSwaggerUI();

app.UseCorrelation();
app.UseWhen(
ctx => ctx.Request.Path.StartsWithSegments(new PathString("/api")),
appBuilder => appBuilder.UseTenantMiddleware());

app.UseProblemDetails();


app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

}

public static ProblemDetailsOptions ConfigureProblemDetails(ProblemDetailsOptions options, bool includeExceptionDetails = true)
{
includeExceptionDetails = includeExceptionDetails && Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";

options.IncludeExceptionDetails = (_context, _exception) => includeExceptionDetails;
options.MapStatusCode = context => new StatusCodeProblemDetails(context.Response.StatusCode);

options.Map<NotImplementedException>(_ex => new StatusCodeProblemDetails(StatusCodes.Status501NotImplemented));

options.Map<Exception>(ex =>
{
var det = new ProblemDetailsException
{
Status = StatusCodes.Status500InternalServerError,
Title = "Unexpected error",
CorrelationId = CorrelationManager.GetCorrelationId()?.ToString(),
Detail = includeExceptionDetails ? ex.Message : "Unexpected error",
Type = ex.GetType().FullName
};
return det;
});

return options;
}
}

public class ProblemDetailsException : Microsoft.AspNetCore.Mvc.ProblemDetails
{
public ProblemDetailsException()
{
}

public string CorrelationId { get; set; }
}
}
67 changes: 56 additions & 11 deletions samples/MultiTenancy/NBB.Todo.Api/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,56 @@
{
"Serilog": {
"MinimumLevel": "Information"
},
"ConnectionStrings": {
"DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true",
"Log_Database": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
},
"Serilog": {
"Properties": {
"ServiceName": "NBB.Todo.Api"
},
"MinimumLevel": {
"Default": "Debug",
"Override": {
"Microsoft": "Information",
"OpenTracing": "Warning",
"System.Net": "Warning"
}
},
"WriteTo": [
{
"Name": "MSSqlServer",
"Args": {
"connectionString": "Log_Database",
"sinkOptionsSection": {
"tableName": "__Logs",
"schemaName": "dbo",
"autoCreateSqlTable": true,
"batchPostingLimit": 5000
},
//"restrictedToMinimumLevel": "Information",
"columnOptionsSection": {
"addStandardColumns": [ "LogEvent" ],
"removeStandardColumns": [ "MessageTemplate", "Properties" ],
"additionalColumns": [
{
"ColumnName": "ServiceName",
"DataType": "varchar",
"DataLength": 200
},
{
"ColumnName": "TenantId",
"DataType": "UniqueIdentifier"
},
{
"ColumnName": "CorrelationId",
"DataType": "UniqueIdentifier"
}
]
}
}
}
]
},

"Messaging": {
"Env": "DEV",
"Source": "Todo.Api",
Expand All @@ -20,15 +67,13 @@
"DefaultConnection": "Server=YOUR_SERVER;Database=NBB_Invoices;User Id=YOUR_USER;Password=YOUR_PASSWORD;MultipleActiveResultSets=true"
}
},
"Tenants": [
{
"TenantId": "f7bfa571-4067-4167-a4c5-dafb71ccdcf7",
"Code": "tenant1"
"Tenants": {
"tenant1": {
"TenantId": "f7bfa571-4067-4167-a4c5-dafb71ccdcf7"
},
{
"TenantId": "a7bfa571-4067-4167-a4c5-dafb71ccdcf7",
"Code": "tenant2"
"tenant2": {
"TenantId": "a7bfa571-4067-4167-a4c5-dafb71ccdcf7"
}
]
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public CreateTodoTaskHandler(ICrudRepository<TodoTask> todoTaskRepository)

public async Task<Unit> Handle(CreateTodoTask request, CancellationToken cancellationToken)
{
//throw new System.Exception("handler exception");
var todoTask = new TodoTask
{
Name = request.Name,
Expand Down
2 changes: 2 additions & 0 deletions samples/MultiTenancy/NBB.Todo.Worker/NBB.Todo.Worker.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
<PackageReference Include="Serilog.AspNetCore" Version="$(SerilogAspNetCorePackageVersion)" />
<PackageReference Include="Serilog.Extensions.Logging" Version="$(SerilogExtensionsLoggingPackageVersion)" />
<PackageReference Include="Serilog.Sinks.Console" Version="$(SerilogSinksConsole)" />
<PackageReference Include="Serilog.Sinks.MSSqlServer" Version="$(SerilogSinksMSSqlServerPackageVersion)" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="$(MediatRPackageVersion)" />
</ItemGroup>

Expand All @@ -36,6 +37,7 @@
<ProjectReference Include="..\..\..\src\Messaging\NBB.Messaging.OpenTracing\NBB.Messaging.OpenTracing.csproj" />
<ProjectReference Include="..\..\..\src\MultiTenancy\NBB.MultiTenancy.Identification.Http\NBB.MultiTenancy.Identification.Http.csproj" />
<ProjectReference Include="..\..\..\src\MultiTenancy\NBB.MultiTenancy.Identification.Messaging\NBB.MultiTenancy.Identification.Messaging.csproj" />
<ProjectReference Include="..\..\..\src\Tools\Serilog\NBB.Tools.Serilog.Enrichers.TenantId\NBB.Tools.Serilog.Enrichers.TenantId.csproj" />
<ProjectReference Include="..\..\..\src\Tools\Serilog\NBB.Tools.Serilog.OpenTracingSink\NBB.Tools.Serilog.OpenTracingSink.csproj" />
<ProjectReference Include="..\NBB.Todo.Data\NBB.Todo.Data.csproj" />
<ProjectReference Include="..\NBB.Todo.PublishedLanguage\NBB.Todo.PublishedLanguage.csproj" />
Expand Down
25 changes: 13 additions & 12 deletions samples/MultiTenancy/NBB.Todo.Worker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
using NBB.MultiTenancy.Abstractions.Repositories;
using Serilog.Events;
using Microsoft.Extensions.Logging;
using NBB.Correlation.Serilog;
using NBB.Tools.Serilog.Enrichers.TenantId;

namespace NBB.Todo.Worker
{
Expand Down Expand Up @@ -45,9 +47,16 @@ public static async Task<int> Main(string[] args)

public static IHost BuildConsoleHost(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(ConfigureLogging)
.ConfigureServices(ConfigureServices)
.UseSerilog()
.UseSerilog((context, services, logConfig) =>
{
logConfig
.ReadFrom.Configuration(context.Configuration)
.Enrich.FromLogContext()
.Enrich.With<CorrelationLogEventEnricher>()
.Enrich.With(services.GetRequiredService<TenantEnricher>())
.WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3} {TenantCode:u}] {Message:lj}{NewLine}{Exception}");
})
.UseConsoleLifetime()
.Build();

Expand All @@ -71,8 +80,8 @@ private static void ConfigureServices(HostBuilderContext hostingContext, IServic
.WithDefaultOptions()
.UsePipeline(builder => builder
.UseCorrelationMiddleware()
.UseExceptionHandlingMiddleware()
.UseTenantMiddleware()
.UseExceptionHandlingMiddleware()
.UseDefaultResiliencyMiddleware()
.UseMediatRMiddleware())
)
Expand All @@ -85,16 +94,8 @@ private static void ConfigureServices(HostBuilderContext hostingContext, IServic
.AddMultiTenantMessaging()
.AddDefaultMessagingTenantIdentification()
.AddTenantRepository<ConfigurationTenantRepository>();
}

private static void ConfigureLogging(HostBuilderContext ctx, ILoggingBuilder _builder)
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(ctx.Configuration)
.MinimumLevel.Override("Microsoft", LogEventLevel.Warning)
.Enrich.FromLogContext()
.WriteTo.Console()
.CreateLogger();
services.AddSingleton<TenantEnricher>();
}
}
}
Loading

0 comments on commit 6bcd832

Please sign in to comment.