Skip to content

Commit

Permalink
WIP - New version of bootstrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
moattarwork committed Mar 12, 2024
1 parent 50fc3ae commit 89ef2e3
Show file tree
Hide file tree
Showing 18 changed files with 465 additions and 70 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using LittleBlocks.Logging.SeriLog;

namespace LittleBlocks.AspNetCore.Bootstrap.Extensions;

public static class ConfigurationExtensions
{
public static AppInfo GetApplicationInfo(this WebApplicationBuilder builder)
{
var appName = builder.Configuration["Application:Name"] ?? builder.Environment.ApplicationName;
var appVersion = builder.Configuration["Application:Version"] ?? "1.0.0";
var appDescription = builder.Configuration["Application:Description"] ?? "";
var appEnvironment = builder.Environment.EnvironmentName;
return new AppInfo(appName, appVersion, appEnvironment, appDescription);
}

public static LoggingContext GetLoggingContext(this WebApplicationBuilder builder)
{
var applicationInfo = builder.GetApplicationInfo();
return new LoggingContext(applicationInfo, applicationInfo.ToTags())
{
Host = "ASPNetCore",
ExcludeEventFilter = "ClientAgent = 'AlwaysOn' or (RequestPath = '/health' and StatusCode < 400)"
};
}

public static HostInfo GetHostInfo(this WebApplicationBuilder builder)
{
var hostType = Enum.TryParse(typeof(HostType), builder.Configuration["Host:Type"], out var result)
? (HostType) result
: HostType.Kestrel;
return new HostInfo(hostType, hostType == HostType.Kestrel);
}

private static string[] ToTags(this AppInfo appInfo)
{
ArgumentNullException.ThrowIfNull(appInfo);

return new[]
{
$"app:{appInfo.Name}",
$"version:{appInfo.Version}",
$"env:{appInfo.Environment}"
};
}
}
3 changes: 3 additions & 0 deletions src/LittleBlocks.AspNetCore.Bootstrap/Extensions/HostInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace LittleBlocks.AspNetCore.Bootstrap.Extensions;

public record HostInfo(HostType Type, bool RequiredSslRedirect);
7 changes: 7 additions & 0 deletions src/LittleBlocks.AspNetCore.Bootstrap/Extensions/HostType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace LittleBlocks.AspNetCore.Bootstrap.Extensions;

public enum HostType
{
Kestrel,
Docker,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using MicroElements.Swashbuckle.FluentValidation.AspNetCore;
using Microsoft.FeatureManagement;
using Microsoft.OpenApi.Models;

namespace LittleBlocks.AspNetCore.Bootstrap.Extensions;

public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCorsWithDefaultPolicy(this IServiceCollection services)
{
if (services == null) throw new ArgumentNullException(nameof(services));

services.AddCors(c =>
c.AddDefaultPolicy(p => p.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin()));
return services;
}

public static IServiceCollection AddTypeMapping(this IServiceCollection services,
Action<IMapperConfigurationExpression> configure)
{
if (services == null) throw new ArgumentNullException(nameof(services));
if (configure == null) throw new ArgumentNullException(nameof(configure));

services.AddTransient<IMapper>(sp => new MapperConfiguration(configure).CreateMapper());

return services;
}

public static IServiceCollection AddOpenApiDocumentation(this IServiceCollection services,
AppInfo appInfo)
{
ArgumentNullException.ThrowIfNull(services);
ArgumentNullException.ThrowIfNull(appInfo);

services.AddSwaggerGen(d =>
{
d.SwaggerDoc("v1", new OpenApiInfo
{
Title = $"{appInfo.Name} - {appInfo.Environment}",
Version = appInfo.Version,
Description = appInfo.Description
});

var xmlFiles = Directory.GetFiles(AppContext.BaseDirectory, "Ardevora.Feeds.Bloomberg.*.xml",
SearchOption.TopDirectoryOnly).ToList();
xmlFiles.ForEach(xmlFile => d.IncludeXmlComments(xmlFile));
});
services.AddFluentValidationRulesToSwagger();

return services;
}

public static IServiceCollection AddFeatures<T>(this IServiceCollection services, IConfiguration configuration)
{
if (configuration == null) throw new ArgumentNullException(nameof(configuration));

var name = typeof(T).Name;
services.AddFeatureManagement(configuration.GetSection(name));

return services;
}

public static IServiceCollection Remove<T>(this IServiceCollection services)
{
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(T));
services.Remove(descriptor);

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using System.Net;
using GlobalExceptionHandler.WebApi;
using LittleBlocks.Exceptions;
using Newtonsoft.Json;

namespace LittleBlocks.AspNetCore.Bootstrap.Extensions;

public static class WebApplicationExtensions
{
public static void UseGlobalExceptionAndLoggingHandler(this WebApplication app)
{
ArgumentNullException.ThrowIfNull(app);

app.UseGlobalExceptionHandler(x =>
{
x.ContentType = "application/json";
x.ResponseBody(s => JsonConvert.SerializeObject(new
{
Message = "An error occurred whilst processing your request"
}));
x.Map<AppException>()
.ToStatusCode(HttpStatusCode.InternalServerError)
.WithBody((e, context) => JsonConvert.SerializeObject(new {e.Message}));

x.OnError((e, context) =>
{
app.Logger.LogError((Exception) e, "Error in processing the request to {Path}", context.Request.Path);
return Task.CompletedTask;
});
});
}

public static void UseHttpsRedirection(this WebApplication app, HostInfo hostInfo)
{
ArgumentNullException.ThrowIfNull(hostInfo);
if (hostInfo.RequiredSslRedirect)
app.UseHttpsRedirection();
}

public static void UseOpenApiDocumentation(this WebApplication app, AppInfo appInfo)
{
ArgumentNullException.ThrowIfNull(app);
ArgumentNullException.ThrowIfNull(appInfo);

var name = $"{appInfo.Name} v{appInfo.Version}";

app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", name);
c.DocumentTitle = name;
});

app.UseReDoc(c =>
{
c.DocumentTitle = name;
c.SpecUrl("/swagger/v1/swagger.json");
});
}

public static void MapDependencyHealthChecks(this WebApplication app)
{
ArgumentNullException.ThrowIfNull(app);

app.MapHealthChecks("/health",
new HealthCheckOptions {ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse});
}

public static IServiceCollection AddDependencyHealthChecks(this IServiceCollection services,
Action<IHealthChecksBuilder>? configure = null)

Check warning on line 70 in src/LittleBlocks.AspNetCore.Bootstrap/Extensions/WebApplicationExtensions.cs

View workflow job for this annotation

GitHub Actions / build

The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
{
ArgumentNullException.ThrowIfNull(services);

var builder = services.AddHealthChecks();
configure?.Invoke(builder);

return services;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// namespace LittleBlocks.AspNetCore.Bootstrap.Extensions;
//
// public static class WebHostBuilderExtensions
// {
// public static void ConfigureAzureKeyVault(this IWebHostBuilder builder,
// Action<AzureKeyVaultOptions>? configure = null)
// {
// if (builder == null) throw new ArgumentNullException(nameof(builder));
//
// var options = new AzureKeyVaultOptions();
// configure?.Invoke(options);
//
// builder.ConfigureAppConfiguration((ctx, c) => { c.ConfigureAzureKeyVault(options); });
// }
// }
4 changes: 4 additions & 0 deletions src/LittleBlocks.AspNetCore/LittleBlocks.AspNetCore.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,11 @@
<PackageReference Include="Serilog.Sinks.Literate" Version="3.0.0" />
<PackageReference Include="Serilog.Sinks.RollingFile" Version="3.3.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.ReDoc" Version="6.5.0" />
<PackageReference Include="AspNetCore.HealthChecks.Uris" Version="8.0.0" />
<PackageReference Include="CorrelationId" Version="3.0.1"/>
<PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="6.0.0"/>
<PackageReference Include="GlobalExceptionHandler" Version="4.0.2"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LittleBlocks.Configurations\LittleBlocks.Configurations.csproj" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using CorrelationId;
using CorrelationId.DependencyInjection;

namespace LittleBlocks.AspNetCore.RequestCorrelation;

public static class CorrelationExtensions
{
public static IServiceCollection AddRequestCorrelation(this IServiceCollection service,
Action<CorrelationIdOptions> configure = null)
{
return service.AddDefaultCorrelationId(options =>
{
options.CorrelationIdGenerator = () => Guid.NewGuid().ToString();
options.AddToLoggingScope = true;
options.EnforceHeader = false;
options.IgnoreRequestHeader = false;
options.IncludeInResponse = true;
options.UpdateTraceIdentifier = true;

configure?.Invoke(options);
});
}

public static void UseRequestCorrelation(this WebApplication app)
{
app.UseCorrelationId();
}
}
16 changes: 5 additions & 11 deletions src/LittleBlocks.Configurations/AppInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,10 @@

namespace LittleBlocks.Configurations;

public sealed class AppInfo
public sealed class AppInfo(string name, string version, string environment, string description = "")
{
public AppInfo(string name, string version, string environment)
{
Name = name;
Version = version;
Environment = environment;
}

public string Name { get; }
public string Version { get; }
public string Environment { get; }
public string Name { get; } = name;
public string Version { get; } = version;
public string Environment { get; } = environment;
public string Description { get; } = description;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

<ItemGroup>
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
18 changes: 18 additions & 0 deletions src/LittleBlocks.Logging.SeriLog/LoggingContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using LittleBlocks.Configurations;
using Microsoft.Extensions.Hosting;

namespace LittleBlocks.Logging.SeriLog;

public record LoggingContext(AppInfo AppInfo, string[] Tags)
{
public string Host { get; init; } = "";
public string ExcludeEventFilter { get; init; } = "";
public bool EnableDebugging { get; init; } = false;
public string DefaultFilePath { get; init; } = @"logs\log.txt";
public LogEventLevel DefaultLogLevel { get; init; } = LogEventLevel.Information;

public bool IsDevelopment()
{
return AppInfo?.Environment == Environments.Development;
}
}
2 changes: 2 additions & 0 deletions src/LittleBlocks.Logging/LittleBlocks.Logging.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="Serilog" Version="3.1.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\LittleBlocks.Configurations\LittleBlocks.Configurations.csproj" />
<ProjectReference Include="..\LittleBlocks.Extensions\LittleBlocks.Extensions.csproj" />
<ProjectReference Include="..\LittleBlocks.Logging.Extensions\LittleBlocks.Logging.Extensions.csproj" />
</ItemGroup>
Expand Down
12 changes: 12 additions & 0 deletions src/LittleBlocks/Exceptions/AppException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace LittleBlocks.Exceptions;

public class AppException : Exception
{
public AppException(string message) : base(message)
{
}

public AppException(string message, Exception innerException) : base(message, innerException)
{
}
}
Loading

0 comments on commit 89ef2e3

Please sign in to comment.