feat: tweaks

This commit is contained in:
Jean Gatto
2023-07-08 11:10:38 -03:00
parent b705d7c6d8
commit 06f7bf2d31
10 changed files with 59 additions and 74 deletions
@@ -12,7 +12,8 @@ public static class ServicesCollectionExtensions
public static void AddApplication(this IServiceCollection services)
{
var executingAssembly = Assembly.GetExecutingAssembly();
services.AddMediatR(executingAssembly);
services.AddValidatorsFromAssemblies(new[] { executingAssembly });
services
.AddMediatR(executingAssembly)
.AddValidatorsFromAssemblies(new[] { executingAssembly });
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ namespace Shop.Core.AppSettings;
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
public sealed class CacheOptions : IAppOptions
{
public const string ConfigSectionPath = nameof(CacheOptions);
static string IAppOptions.ConfigSectionPath => nameof(CacheOptions);
public int AbsoluteExpirationInHours { get; private init; }
public int SlidingExpirationInSeconds { get; private init; }
@@ -7,7 +7,7 @@ namespace Shop.Core.AppSettings;
[SuppressMessage("ReSharper", "UnusedAutoPropertyAccessor.Local")]
public sealed class ConnectionOptions : IAppOptions
{
public const string ConfigSectionPath = "ConnectionStrings";
static string IAppOptions.ConfigSectionPath => "ConnectionStrings";
[Required]
public string SqlConnection { get; private init; }
@@ -6,17 +6,17 @@ namespace Shop.Core.Extensions;
public static class ConfigurationExtensions
{
private static readonly Action<BinderOptions> ConfigureBinderOptions
= options => options.BindNonPublicProperties = true;
private static readonly Action<BinderOptions> ConfigureBinderOptions = options =>
options.BindNonPublicProperties = true;
/// <summary>
/// Get options from IConfiguration object.
/// </summary>
/// <typeparam name="TOptions">The type of options to retrieve.</typeparam>
/// <param name="configuration">The IConfiguration object.</param>
/// <param name="configSectionPath">The configuration section path.</param>
/// <returns>The options object.</returns>
public static TOptions GetOptions<TOptions>(this IConfiguration configuration, string configSectionPath)
where TOptions : class, IAppOptions =>
configuration.GetRequiredSection(configSectionPath).Get<TOptions>(ConfigureBinderOptions);
public static TOptions GetOptions<TOptions>(this IConfiguration configuration) where TOptions : class, IAppOptions
=> configuration
.GetRequiredSection(TOptions.ConfigSectionPath)
.Get<TOptions>(ConfigureBinderOptions);
}
@@ -11,38 +11,30 @@ namespace Shop.Core.Extensions;
[ExcludeFromCodeCoverage]
public static class ServicesCollectionExtensions
{
private static readonly Action<BinderOptions> ConfigureBinderOptions
= options => options.BindNonPublicProperties = true;
private static readonly Action<BinderOptions> ConfigureBinderOptions = options =>
options.BindNonPublicProperties = true;
public static void AddCorrelationGenerator(this IServiceCollection services) =>
services.AddScoped<ICorrelationIdGenerator, CorrelationIdGenerator>();
public static void ConfigureAppSettings(this IServiceCollection services)
{
services.AddOptionsWithValidation<ConnectionOptions>(ConnectionOptions.ConfigSectionPath);
services.AddOptionsWithValidation<CacheOptions>(CacheOptions.ConfigSectionPath);
}
public static void ConfigureAppSettings(this IServiceCollection services) =>
services
.AddOptionsWithValidation<ConnectionOptions>()
.AddOptionsWithValidation<CacheOptions>();
/// <summary>
/// Adds options with validation to the service collection.
/// </summary>
/// <typeparam name="TOptions">The type of options to add.</typeparam>
/// <param name="services">The service collection.</param>
/// <param name="configSectionPath">The configuration section path.</param>
private static void AddOptionsWithValidation<TOptions>(this IServiceCollection services, string configSectionPath)
private static IServiceCollection AddOptionsWithValidation<TOptions>(this IServiceCollection services)
where TOptions : class, IAppOptions
{
// Adds options of type TOptions to the service collection.
services
return services
.AddOptions<TOptions>()
// Binds the configuration section specified by configSectionPath to the options.
.BindConfiguration(configSectionPath, ConfigureBinderOptions)
// Validates the options using data annotations.
.BindConfiguration(TOptions.ConfigSectionPath, ConfigureBinderOptions)
.ValidateDataAnnotations()
// Performs additional validation on start.
.ValidateOnStart();
.ValidateOnStart()
.Services;
}
}
@@ -5,4 +5,8 @@ namespace Shop.Core.SharedKernel;
/// </summary>
public interface IAppOptions
{
/// <summary>
/// The configuration section path.
/// </summary>
static abstract string ConfigSectionPath { get; }
}
@@ -14,24 +14,18 @@ namespace Shop.Infrastructure.Extensions;
[ExcludeFromCodeCoverage]
public static class ServicesCollectionExtensions
{
public static void AddMemoryCacheService(this IServiceCollection services)
=> services.AddScoped<ICacheService, MemoryCacheService>();
public static void AddMemoryCacheService(this IServiceCollection services) =>
services.AddScoped<ICacheService, MemoryCacheService>();
public static void AddDistributedCacheService(this IServiceCollection services)
=> services.AddScoped<ICacheService, DistributedCacheService>();
public static void AddDistributedCacheService(this IServiceCollection services) =>
services.AddScoped<ICacheService, DistributedCacheService>();
public static void AddInfrastructure(this IServiceCollection services)
{
// MediatR Pipelines
services.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
// Repositories
services.AddScoped<IEventStoreRepository, EventStoreRepository>();
services.AddScoped<ICustomerWriteOnlyRepository, CustomerWriteOnlyRepository>();
// Database Contexts
services.AddScoped<WriteDbContext>();
services.AddScoped<EventStoreDbContext>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
}
public static void AddInfrastructure(this IServiceCollection services) =>
services
.AddScoped(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>))
.AddScoped<IEventStoreRepository, EventStoreRepository>()
.AddScoped<ICustomerWriteOnlyRepository, CustomerWriteOnlyRepository>()
.AddScoped<WriteDbContext>()
.AddScoped<EventStoreDbContext>()
.AddScoped<IUnitOfWork, UnitOfWork>();
}
@@ -56,7 +56,7 @@ internal static class ServicesCollectionExtensions
public static void AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
{
var connectionOptions = configuration.GetOptions<ConnectionOptions>(ConnectionOptions.ConfigSectionPath);
var connectionOptions = configuration.GetOptions<ConnectionOptions>();
var healthCheckBuilder = services
.AddHealthChecks()
@@ -79,14 +79,12 @@ internal static class ServicesCollectionExtensions
public static void AddCacheService(this IServiceCollection services, IConfiguration configuration)
{
var connectionOptions = configuration.GetOptions<ConnectionOptions>(ConnectionOptions.ConfigSectionPath);
var connectionOptions = configuration.GetOptions<ConnectionOptions>();
if (connectionOptions.CacheConnection.IsInMemoryCache())
{
// ASP.NET Core Memory Cache.
services.AddMemoryCache();
// Shop Infra Service.
services.AddMemoryCacheService();
services
.AddMemoryCache() // ASP.NET Core Memory Cache.
.AddMemoryCacheService();// Shop Infra Service.
}
else
{
@@ -96,10 +94,7 @@ internal static class ServicesCollectionExtensions
{
options.InstanceName = "master";
options.Configuration = connectionOptions.CacheConnection;
});
// Shop Infra Service.
services.AddDistributedCacheService();
}).AddDistributedCacheService(); // Shop Infra Service.
}
}
@@ -116,13 +111,10 @@ internal static class ServicesCollectionExtensions
var connectionOptions = serviceProvider.GetOptions<ConnectionOptions>();
optionsBuilder.UseSqlServer(connectionOptions.SqlConnection, sqlServerOptions =>
{
sqlServerOptions.MigrationsAssembly(MigrationsAssembly);
// Configure connection resiliency with retry on failure and a command timeout of 60 seconds.
sqlServerOptions.EnableRetryOnFailure(3);
sqlServerOptions.CommandTimeout(60);
}).UseQueryTrackingBehavior(queryTrackingBehavior);
sqlServerOptions
.MigrationsAssembly(MigrationsAssembly)
.EnableRetryOnFailure(3) // Configure connection resiliency with retry on failure.
.CommandTimeout(60)).UseQueryTrackingBehavior(queryTrackingBehavior);
// Log retry attempts for execution strategy.
optionsBuilder.LogTo(
@@ -145,6 +137,10 @@ internal static class ServicesCollectionExtensions
// Enable detailed errors and sensitive data logging if the environment is "development".
var environment = serviceProvider.GetRequiredService<IHostEnvironment>();
if (environment.IsDevelopment())
optionsBuilder.EnableDetailedErrors().EnableSensitiveDataLogging();
{
optionsBuilder
.EnableDetailedErrors()
.EnableSensitiveDataLogging();
}
}
}
@@ -20,13 +20,11 @@ public static class ServicesCollectionExtensions
public static void AddQuery(this IServiceCollection services)
{
var executingAssembly = Assembly.GetExecutingAssembly();
services.AddMediatR(executingAssembly);
// Add AutoMapper as a singleton instance
services.AddSingleton<IMapper>(new Mapper(new MapperConfiguration(cfg => cfg.AddMaps(executingAssembly))));
services.AddValidatorsFromAssembly(executingAssembly);
services.AddSingleton<IReadDbContext, ReadDbContext>();
services.AddScoped<ICustomerReadOnlyRepository, CustomerReadOnlyRepository>();
services
.AddMediatR(executingAssembly)
.AddSingleton<IMapper>(new Mapper(new MapperConfiguration(cfg => cfg.AddMaps(executingAssembly))))
.AddValidatorsFromAssembly(executingAssembly).AddSingleton<IReadDbContext, ReadDbContext>()
.AddScoped<ICustomerReadOnlyRepository, CustomerReadOnlyRepository>();
ConfigureMongoDb();
}
@@ -28,7 +28,7 @@ public class ConfigurationExtensionsTests
var configuration = configurationBuilder.Build();
// Act
var act = configuration.GetOptions<CacheOptions>(CacheOptions.ConfigSectionPath);
var act = configuration.GetOptions<CacheOptions>();
// Assert
act.Should().NotBeNull();