Generator Changes at 9/27/2025 8:46:36 AM
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CMSMicroservice.Application\CMSMicroservice.Application.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -0,0 +1,24 @@
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace MediatR;
|
||||
|
||||
public static class MediatorExtensions
|
||||
{
|
||||
public static async Task DispatchDomainEvents(this IMediator mediator, DbContext context)
|
||||
{
|
||||
var entities = context.ChangeTracker
|
||||
.Entries<BaseEntity>()
|
||||
.Where(e => e.Entity.DomainEvents.Any())
|
||||
.Select(e => e.Entity);
|
||||
|
||||
var domainEvents = entities
|
||||
.SelectMany(e => e.DomainEvents)
|
||||
.ToList();
|
||||
|
||||
entities.ToList().ForEach(e => e.ClearDomainEvents());
|
||||
|
||||
foreach (var domainEvent in domainEvents)
|
||||
await mediator.Publish(domainEvent);
|
||||
}
|
||||
}
|
||||
92
src/CMSMicroservice.Infrastructure/ConfigureServices.cs
Normal file
92
src/CMSMicroservice.Infrastructure/ConfigureServices.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Infrastructure.Persistence;
|
||||
using CMSMicroservice.Infrastructure.Persistence.Interceptors;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
public static class ConfigureServices
|
||||
{
|
||||
public static IServiceCollection AddInfrastructureServices(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddScoped<AuditableEntitySaveChangesInterceptor>();
|
||||
services.AddScoped<ApplicationDbContextInitialiser>();
|
||||
services.AddScoped<IApplicationDbContext>(p => p.GetRequiredService<ApplicationDbContext>());
|
||||
if (configuration.GetValue<bool>("UseInMemoryDatabase"))
|
||||
{
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseInMemoryDatabase("MyMemoryDb"));
|
||||
}
|
||||
else
|
||||
{
|
||||
services.AddDbContext<ApplicationDbContext>(options =>
|
||||
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection"),
|
||||
builder => builder.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
|
||||
}
|
||||
#region AddAuthentication
|
||||
|
||||
var message = "";
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(jwtBearerOptions =>
|
||||
{
|
||||
jwtBearerOptions.Authority = configuration["Authentication:Authority"];
|
||||
jwtBearerOptions.Audience = configuration["Authentication:Audience"];
|
||||
jwtBearerOptions.TokenValidationParameters.ValidateAudience = false;
|
||||
jwtBearerOptions.TokenValidationParameters.ValidateIssuer = true;
|
||||
jwtBearerOptions.TokenValidationParameters.ValidateIssuerSigningKey = false;
|
||||
try
|
||||
{
|
||||
jwtBearerOptions.Events = new JwtBearerEvents
|
||||
{
|
||||
OnAuthenticationFailed = ctx =>
|
||||
{
|
||||
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
message += "From OnAuthenticationFailed:\n";
|
||||
message += ctx.Exception.Message;
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
|
||||
OnChallenge = ctx =>
|
||||
{
|
||||
message += "From OnChallenge:\n";
|
||||
ctx.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||
ctx.Response.ContentType = "text/plain";
|
||||
return ctx.Response.WriteAsync(message);
|
||||
},
|
||||
|
||||
OnMessageReceived = ctx =>
|
||||
{
|
||||
message = "From OnMessageReceived:\n";
|
||||
ctx.Request.Headers.TryGetValue("Authorization", out var BearerToken);
|
||||
if (BearerToken.Count == 0)
|
||||
BearerToken = "no Bearer token sent\n";
|
||||
message += "Authorization Header sent: " + BearerToken + "\n";
|
||||
return Task.CompletedTask;
|
||||
},
|
||||
|
||||
OnTokenValidated = ctx =>
|
||||
{
|
||||
Debug.WriteLine("token: " + ctx.SecurityToken.ToString());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
|
||||
services.AddAuthorization();
|
||||
|
||||
#endregion
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
4
src/CMSMicroservice.Infrastructure/GlobalUsings.cs
Normal file
4
src/CMSMicroservice.Infrastructure/GlobalUsings.cs
Normal file
@@ -0,0 +1,4 @@
|
||||
global using System.Threading;
|
||||
global using System.Threading.Tasks;
|
||||
global using System;
|
||||
global using System.Linq;
|
||||
@@ -0,0 +1,49 @@
|
||||
using System.Reflection;
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using CMSMicroservice.Infrastructure.Persistence.Interceptors;
|
||||
using MediatR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence;
|
||||
|
||||
public class ApplicationDbContext : DbContext, IApplicationDbContext
|
||||
{
|
||||
private readonly IMediator _mediator;
|
||||
private readonly AuditableEntitySaveChangesInterceptor _auditableEntitySaveChangesInterceptor;
|
||||
|
||||
public ApplicationDbContext(
|
||||
DbContextOptions<ApplicationDbContext> options,
|
||||
IMediator mediator,
|
||||
AuditableEntitySaveChangesInterceptor auditableEntitySaveChangesInterceptor)
|
||||
: base(options)
|
||||
{
|
||||
_mediator = mediator;
|
||||
_auditableEntitySaveChangesInterceptor = auditableEntitySaveChangesInterceptor;
|
||||
}
|
||||
protected override void OnModelCreating(ModelBuilder builder)
|
||||
{
|
||||
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
|
||||
builder.HasDefaultSchema("CMS");
|
||||
base.OnModelCreating(builder);
|
||||
}
|
||||
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
|
||||
{
|
||||
optionsBuilder.AddInterceptors(_auditableEntitySaveChangesInterceptor);
|
||||
}
|
||||
|
||||
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
await _mediator.DispatchDomainEvents(this);
|
||||
|
||||
return await base.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
public DbSet<User> Users => Set<User>();
|
||||
public DbSet<UserAddress> UserAddresss => Set<UserAddress>();
|
||||
public DbSet<Package> Packages => Set<Package>();
|
||||
public DbSet<UserOrder> UserOrders => Set<UserOrder>();
|
||||
public DbSet<Role> Roles => Set<Role>();
|
||||
public DbSet<UserRole> UserRoles => Set<UserRole>();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence;
|
||||
|
||||
public class ApplicationDbContextInitialiser
|
||||
{
|
||||
private readonly ApplicationDbContext _context;
|
||||
private readonly ILogger<ApplicationDbContextInitialiser> _logger;
|
||||
|
||||
public ApplicationDbContextInitialiser(ApplicationDbContext context, ILogger<ApplicationDbContextInitialiser> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InitialiseAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_context.Database.IsSqlServer())
|
||||
{
|
||||
await _context.Database.MigrateAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred while initialising the database.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SeedAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await TrySeedAsync();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "An error occurred while seeding the database.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public async Task TrySeedAsync()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class PackageConfiguration : IEntityTypeConfiguration<Package>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Package> builder)
|
||||
{
|
||||
builder.HasQueryFilter(p => !p.IsDeleted);
|
||||
builder.Ignore(entity => entity.DomainEvents);
|
||||
builder.HasKey(entity => entity.Id);
|
||||
builder.Property(entity => entity.Id).UseIdentityColumn();
|
||||
builder.Property(entity => entity.Title).IsRequired(true);
|
||||
builder.Property(entity => entity.Description).IsRequired(true);
|
||||
builder.Property(entity => entity.ImagePath).IsRequired(true);
|
||||
builder.Property(entity => entity.Price).IsRequired(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class RoleConfiguration : IEntityTypeConfiguration<Role>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<Role> builder)
|
||||
{
|
||||
builder.HasQueryFilter(p => !p.IsDeleted);
|
||||
builder.Ignore(entity => entity.DomainEvents);
|
||||
builder.HasKey(entity => entity.Id);
|
||||
builder.Property(entity => entity.Id).UseIdentityColumn();
|
||||
builder.Property(entity => entity.Name).IsRequired(true);
|
||||
builder.Property(entity => entity.Title).IsRequired(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class UserAddressConfiguration : IEntityTypeConfiguration<UserAddress>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<UserAddress> builder)
|
||||
{
|
||||
builder.HasQueryFilter(p => !p.IsDeleted);
|
||||
builder.Ignore(entity => entity.DomainEvents);
|
||||
builder.HasKey(entity => entity.Id);
|
||||
builder.Property(entity => entity.Id).UseIdentityColumn();
|
||||
builder
|
||||
.HasOne(entity => entity.User)
|
||||
.WithMany(entity => entity.UserAddresss)
|
||||
.HasForeignKey(entity => entity.UserId)
|
||||
.IsRequired(true);
|
||||
builder.Property(entity => entity.Title).IsRequired(true);
|
||||
builder.Property(entity => entity.Address).IsRequired(true);
|
||||
builder.Property(entity => entity.PostalCode).IsRequired(true);
|
||||
builder.Property(entity => entity.IsDefault).IsRequired(true);
|
||||
builder.Property(entity => entity.CityId).IsRequired(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class UserConfiguration : IEntityTypeConfiguration<User>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<User> builder)
|
||||
{
|
||||
builder.HasQueryFilter(p => !p.IsDeleted);
|
||||
builder.Ignore(entity => entity.DomainEvents);
|
||||
builder.HasKey(entity => entity.Id);
|
||||
builder.Property(entity => entity.Id).UseIdentityColumn();
|
||||
builder.Property(entity => entity.FirstName).IsRequired(false);
|
||||
builder.Property(entity => entity.LastName).IsRequired(false);
|
||||
builder.Property(entity => entity.Mobile).IsRequired(true);
|
||||
builder.Property(entity => entity.NationalCode).IsRequired(false);
|
||||
builder.Property(entity => entity.AvatarPath).IsRequired(false);
|
||||
builder
|
||||
.HasOne(entity => entity.Parent)
|
||||
.WithMany(entity => entity.Users)
|
||||
.HasForeignKey(entity => entity.ParentId)
|
||||
.IsRequired(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class UserOrderConfiguration : IEntityTypeConfiguration<UserOrder>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<UserOrder> builder)
|
||||
{
|
||||
builder.HasQueryFilter(p => !p.IsDeleted);
|
||||
builder.Ignore(entity => entity.DomainEvents);
|
||||
builder.HasKey(entity => entity.Id);
|
||||
builder.Property(entity => entity.Id).UseIdentityColumn();
|
||||
builder.Property(entity => entity.Price).IsRequired(true);
|
||||
builder
|
||||
.HasOne(entity => entity.Package)
|
||||
.WithMany(entity => entity.UserOrders)
|
||||
.HasForeignKey(entity => entity.PackageId)
|
||||
.IsRequired(true);
|
||||
builder.Property(entity => entity.TransactionId).IsRequired(false);
|
||||
builder.Property(entity => entity.PaymentStatus).IsRequired(true);
|
||||
builder.Property(entity => entity.PaymentDate).IsRequired(false);
|
||||
builder
|
||||
.HasOne(entity => entity.User)
|
||||
.WithMany(entity => entity.UserOrders)
|
||||
.HasForeignKey(entity => entity.UserId)
|
||||
.IsRequired(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using CMSMicroservice.Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Configurations;
|
||||
|
||||
public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>
|
||||
{
|
||||
public void Configure(EntityTypeBuilder<UserRole> builder)
|
||||
{
|
||||
builder.HasQueryFilter(p => !p.IsDeleted);
|
||||
builder.Ignore(entity => entity.DomainEvents);
|
||||
builder.HasKey(entity => entity.Id);
|
||||
builder.Property(entity => entity.Id).UseIdentityColumn();
|
||||
builder
|
||||
.HasOne(entity => entity.Role)
|
||||
.WithMany(entity => entity.UserRoles)
|
||||
.HasForeignKey(entity => entity.RoleId)
|
||||
.IsRequired(true);
|
||||
builder
|
||||
.HasOne(entity => entity.User)
|
||||
.WithMany(entity => entity.UserRoles)
|
||||
.HasForeignKey(entity => entity.UserId)
|
||||
.IsRequired(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
using CMSMicroservice.Application.Common.Interfaces;
|
||||
using CMSMicroservice.Domain.Common;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking;
|
||||
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||
|
||||
namespace CMSMicroservice.Infrastructure.Persistence.Interceptors;
|
||||
|
||||
public class AuditableEntitySaveChangesInterceptor : SaveChangesInterceptor
|
||||
{
|
||||
private readonly ICurrentUserService _currentUserService;
|
||||
|
||||
public AuditableEntitySaveChangesInterceptor(
|
||||
ICurrentUserService currentUserService)
|
||||
{
|
||||
_currentUserService = currentUserService;
|
||||
}
|
||||
public override InterceptionResult<int> SavingChanges(DbContextEventData eventData, InterceptionResult<int> result)
|
||||
{
|
||||
UpdateEntities(eventData.Context);
|
||||
return base.SavingChanges(eventData, result);
|
||||
}
|
||||
|
||||
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default)
|
||||
{
|
||||
UpdateEntities(eventData.Context);
|
||||
return base.SavingChangesAsync(eventData, result, cancellationToken);
|
||||
}
|
||||
|
||||
public void UpdateEntities(DbContext? context)
|
||||
{
|
||||
if (context == null) return;
|
||||
|
||||
foreach (var entry in context.ChangeTracker.Entries<BaseAuditableEntity>())
|
||||
{
|
||||
if (entry.State == EntityState.Added)
|
||||
{
|
||||
entry.Entity.CreatedBy = _currentUserService.UserId;
|
||||
entry.Entity.Created = DateTime.Now;
|
||||
}
|
||||
|
||||
if (entry.State == EntityState.Added || entry.State == EntityState.Modified || entry.HasChangedOwnedEntities())
|
||||
{
|
||||
entry.Entity.LastModifiedBy = _currentUserService.UserId;
|
||||
entry.Entity.LastModified = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public static class Extensions
|
||||
{
|
||||
public static bool HasChangedOwnedEntities(this EntityEntry entry) =>
|
||||
entry.References.Any(r =>
|
||||
r.TargetEntry != null &&
|
||||
r.TargetEntry.Metadata.IsOwned() &&
|
||||
(r.TargetEntry.State == EntityState.Added || r.TargetEntry.State == EntityState.Modified));
|
||||
}
|
||||
Reference in New Issue
Block a user