Skip to content

Commit

Permalink
optimize and centralize auditable entity interceptor
Browse files Browse the repository at this point in the history
  • Loading branch information
mdemrulkayes committed Apr 18, 2024
1 parent fe52ca3 commit 5d32cab
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 125 deletions.
2 changes: 1 addition & 1 deletion src/API/Quizzer.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
});

builder.Services.AddMediatRRequestLoggingBehaviour();
builder.Services.AddMediatRFluentValidationBehaviour();
builder.Services.AddMediatRFluentValidationBehaviour(mediatRAssemblies);

builder.Services.RegisterJwtSwagger();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@
using Modules.Identity.Persistence;
using Modules.Identity.Constants;
using Modules.Identity.Entities;
using Modules.Identity.Features.Registration;
using Microsoft.AspNetCore.Builder;
using Modules.Identity.Persistence.Interceptors;
using Serilog;
using FluentValidation;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Modules.Identity.Features.Login;
using Modules.Identity.Features.Login.Services;
using Modules.Identity.Features.Registration.Services;
using SharedKernel.Infrastructure.Interceptors;

namespace Modules.Identity;
public static class ServiceCollectionExtensions
Expand All @@ -31,12 +29,9 @@ public static class ServiceCollectionExtensions

mediatRAssembly.Add(typeof(ServiceCollectionExtensions).Assembly);

services.AddScoped<IValidator<UserRegistrationCommand>, UserRegistrationCommandValidator>();
services.AddScoped<IUserRegistrationService, UserRegistrationService>();

services.AddScoped<IValidator<LoginCommand>, LoginCommandValidator>();
services.AddScoped<IUserRegistrationService, UserRegistrationService>();
services.AddScoped<ILoginService, LoginService>();

services.Configure<JwtConfiguration>(configuration.GetSection(nameof(JwtConfiguration)));

logger.Information("{Module} registered successfully", "Identity");
Expand All @@ -47,7 +42,7 @@ public static class ServiceCollectionExtensions
private static void RegisterIdentityDatabase(this IServiceCollection services, ILogger logger,
IConfiguration configuration)
{
services.AddScoped<IdentityModuleUpdateAuditableEntityInterceptor>();
services.AddScoped<PopulateAuditableEntityInterceptor>();
services.AddDbContext<IdentityModuleDbContext>((sp, opt) =>
{
opt.UseSqlServer(configuration.GetConnectionString("IdentityModuleDbContext"), optBuilder =>
Expand All @@ -56,7 +51,7 @@ public static class ServiceCollectionExtensions
optBuilder.MigrationsHistoryTable(IdentityModuleConstants.MigrationHistoryTableName,
IdentityModuleConstants.SchemaName);
optBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
}).AddInterceptors(sp.GetRequiredService<IdentityModuleUpdateAuditableEntityInterceptor>());
}).AddInterceptors(sp.GetRequiredService<PopulateAuditableEntityInterceptor>());
});

RegisterIdentity(services, configuration);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ public CreateTagCommandValidator(ITagRepository repository)
RuleFor(x => x.Name)
.NotEmpty()
.WithMessage("Name can not be empty")
.Length(5, 50)
.WithMessage("Name can not be less than 5 characters and can not be more than 50 characters")
.MustAsync(async (name, token) =>
{
var isNameAlreadyExists = await repository.AnyAsync(x =>
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
using System.Reflection;
using Modules.Question.Core.QuestionAggregate;
using Modules.Question.Core.Tag;
using Modules.Question.Infrastructure.Data.Interceptors;
using Modules.Question.Infrastructure.Persistence;
using SharedKernel.Core;
using SharedKernel.Infrastructure.Interceptors;

namespace Modules.Question.Infrastructure;
public static class ServiceCollectionExtensions
Expand All @@ -22,7 +22,7 @@ public static class ServiceCollectionExtensions
{
mediatRAssembly.Add(typeof(ServiceCollectionExtensions).Assembly);

services.AddScoped<QuestionModuleUpdateAuditableEntityInterceptor>();
services.AddScoped<PopulateAuditableEntityInterceptor>();
services.AddDbContext<QuestionModuleDbContext>((serviceProvider, opt) =>
{
opt.UseSqlServer(configuration.GetConnectionString("QuestionModuleDbContext"), optBuilder =>
Expand All @@ -31,7 +31,7 @@ public static class ServiceCollectionExtensions
optBuilder.MigrationsHistoryTable(QuestionModuleConstants.MigrationHistoryTableName,
QuestionModuleConstants.SchemaName);
optBuilder.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
}).AddInterceptors(serviceProvider.GetRequiredService<QuestionModuleUpdateAuditableEntityInterceptor>());
}).AddInterceptors(serviceProvider.GetRequiredService<PopulateAuditableEntityInterceptor>());
});
logger.Information("Question module db context registered");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ public static IServiceCollection AddMediatRRequestLoggingBehaviour(this IService
return services;
}

public static IServiceCollection AddMediatRFluentValidationBehaviour(this IServiceCollection services)
public static IServiceCollection AddMediatRFluentValidationBehaviour(this IServiceCollection services, List<Assembly> mediatRAssemblies)
{
ValidatorOptions.Global.DefaultClassLevelCascadeMode = CascadeMode.Continue;
ValidatorOptions.Global.DefaultRuleLevelCascadeMode = CascadeMode.Stop;
services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly(), includeInternalTypes: true);
services.AddValidatorsFromAssemblies(mediatRAssemblies, includeInternalTypes: true);

services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>));

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Diagnostics;
using SharedKernel.Core;

namespace SharedKernel.Infrastructure.Interceptors;
public sealed class PopulateAuditableEntityInterceptor(ITimeProvider timeProvider, IUser user) : SaveChangesInterceptor
{
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
if (eventData.Context is not null)
{
UpdateIdentityModuleAuditableEntity(eventData.Context);
}
return base.SavingChangesAsync(eventData, result, cancellationToken);
}

private void UpdateIdentityModuleAuditableEntity(DbContext context)
{
var entries = context.ChangeTracker.Entries()
.Where(x => x.State != EntityState.Detached && x.State != EntityState.Unchanged);

foreach (var entry in entries)
{
switch (entry.State)
{
case EntityState.Added:
{
if (entry.Entity is not ICreatedAuditableEntity addedEntity) continue;
addedEntity.CreatedBy = user.Id != null ?
Guid.Parse(user.Id) :
null;
addedEntity.CreatedDate = timeProvider.TimeNow;
break;
}
case EntityState.Modified:
{
if (entry.Entity is not IUpdatedAuditableEntity updatedEntity) continue;
updatedEntity.UpdatedBy = user.Id != null ?
Guid.Parse(user.Id) :
null;
updatedEntity.UpdatedDate = timeProvider.TimeNow;
break;
}
case EntityState.Deleted:
default:
{
if (entry.Entity is not IDeletedAuditableEntity updatedEntity) continue;
updatedEntity.DeletedBy = user.Id != null ?
Guid.Parse(user.Id) :
null;
updatedEntity.DeletedDate = timeProvider.TimeNow;
updatedEntity.IsDeleted = true;
entry.State = EntityState.Modified;
break;
}
}
}
}
}

0 comments on commit 5d32cab

Please sign in to comment.