Introduced a validation pipeline using FluentValidation and MediatR to enhance request validation. Added the following: - Registered FluentValidation and MediatR dependencies in `ReC.Application.csproj`. - Updated `DependencyInjection.cs` to register validators and MediatR behaviors, including `ValidationBehavior<,>`. - Added `ValidationBehavior<TRequest, TResponse>` to handle request validation in the MediatR pipeline. - Created `ReadOutResQueryValidator` to enforce validation rules for `ReadOutResQuery`. - Refactored namespaces and imports for better organization. These changes improve extensibility, maintainability, and separation of concerns in the application.
116 lines
3.9 KiB
C#
116 lines
3.9 KiB
C#
using MediatR;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using ReC.Application.Common.Behaviors;
|
|
using ReC.Application.Common.Options;
|
|
using System.Reflection;
|
|
using FluentValidation;
|
|
|
|
namespace ReC.Application;
|
|
|
|
public static class DependencyInjection
|
|
{
|
|
public static IServiceCollection AddRecServices(this IServiceCollection services, Action<ConfigurationOptions> options)
|
|
{
|
|
var configOpt = new ConfigurationOptions();
|
|
options.Invoke(configOpt);
|
|
|
|
configOpt.EnsureRequiredServices();
|
|
|
|
configOpt.ApplyConfigurations(services);
|
|
|
|
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
|
|
|
services.AddAutoMapper(cfg =>
|
|
{
|
|
cfg.AddMaps(Assembly.GetExecutingAssembly());
|
|
cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey;
|
|
});
|
|
|
|
services.AddMediatR(cfg =>
|
|
{
|
|
cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly());
|
|
cfg.AddOpenBehaviors([typeof(BodyQueryBehavior<,>), typeof(HeaderQueryBehavior<,>)]);
|
|
cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
|
|
cfg.LicenseKey = configOpt.LuckyPennySoftwareLicenseKey;
|
|
});
|
|
|
|
services.AddHttpClient();
|
|
|
|
return services;
|
|
}
|
|
|
|
public class ConfigurationOptions
|
|
{
|
|
|
|
#region Required Services
|
|
private readonly Dictionary<string, bool> _requiredServices = new()
|
|
{
|
|
{ nameof(ConfigureRecActions), false },
|
|
{ nameof(LuckyPennySoftwareLicenseKey), false }
|
|
};
|
|
|
|
internal void EnsureRequiredServices()
|
|
{
|
|
var missingServices = _requiredServices
|
|
.Where(kvp => !kvp.Value)
|
|
.Select(kvp => kvp.Key.Replace("Configure", string.Empty));
|
|
if (missingServices.Any())
|
|
throw new InvalidOperationException($"The following required services were not configured: {string.Join(", ", missingServices)}");
|
|
}
|
|
#endregion Required Services
|
|
|
|
#region Configuration
|
|
private readonly Queue<Action<IServiceCollection>> _configActions = new();
|
|
|
|
internal void ApplyConfigurations(IServiceCollection services)
|
|
{
|
|
while (_configActions.Count > 0)
|
|
{
|
|
var action = _configActions.Dequeue();
|
|
action(services);
|
|
}
|
|
}
|
|
#endregion Configuration
|
|
|
|
#region LuckyPennySoftwareLicenseKey
|
|
private string? _luckyPennySoftwareLicenseKey;
|
|
|
|
public string? LuckyPennySoftwareLicenseKey
|
|
{
|
|
get => _luckyPennySoftwareLicenseKey;
|
|
set
|
|
{
|
|
_luckyPennySoftwareLicenseKey = value;
|
|
if (value is not null)
|
|
_requiredServices[nameof(LuckyPennySoftwareLicenseKey)] = true;
|
|
}
|
|
}
|
|
#endregion LuckyPennySoftwareLicenseKey
|
|
|
|
#region ConfigureRecActions
|
|
public ConfigurationOptions ConfigureRecActions(Action<RecActionOptions> configure)
|
|
{
|
|
_configActions.Enqueue(services => services.Configure(configure));
|
|
|
|
if(_requiredServices[nameof(ConfigureRecActions)])
|
|
throw new InvalidOperationException("RecActionOptions have already been configured.");
|
|
_requiredServices[nameof(ConfigureRecActions)] = true;
|
|
|
|
return this;
|
|
}
|
|
|
|
public ConfigurationOptions ConfigureRecActions(IConfiguration configuration)
|
|
{
|
|
_configActions.Enqueue(services => services.Configure<RecActionOptions>(configuration));
|
|
|
|
if (_requiredServices[nameof(ConfigureRecActions)])
|
|
throw new InvalidOperationException("RecActionOptions have already been configured.");
|
|
_requiredServices[nameof(ConfigureRecActions)] = true;
|
|
|
|
return this;
|
|
}
|
|
#endregion ConfigureRecActions
|
|
}
|
|
}
|