Skip to content

Commit

Permalink
Merge pull request #11 from sj-distributor/setting-and-repo
Browse files Browse the repository at this point in the history
Add settings infrastructure and refactor repo pattern
  • Loading branch information
linwenda authored Apr 10, 2023
2 parents a6b010e + 11894c8 commit e4459de
Show file tree
Hide file tree
Showing 27 changed files with 317 additions and 167 deletions.
3 changes: 1 addition & 2 deletions src/Wax.Api/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,11 @@ public void ConfigureContainer(ContainerBuilder builder)
var serviceProvider = _serviceCollection.BuildServiceProvider();

var currentUser = serviceProvider.GetRequiredService<ICurrentUser>();
var connectionString = Configuration.GetConnectionString("Default");

// Register your own things directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory
// for you.
builder.RegisterModule(new ApplicationModule(Log.Logger, currentUser, connectionString,
builder.RegisterModule(new ApplicationModule(Log.Logger, currentUser, Configuration,
typeof(Startup).Assembly));
}

Expand Down
31 changes: 25 additions & 6 deletions src/Wax.Core/ApplicationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
using Mediator.Net;
using Mediator.Net.Autofac;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Serilog;
using Wax.Core.Data;
using Wax.Core.DependencyInjection;
using Wax.Core.Middlewares.FluentMessageValidator;
using Wax.Core.Middlewares.Logging;
using Wax.Core.Middlewares.UnitOfWorks;
using Wax.Core.Repositories;
using Wax.Core.Services.Identity;
using Wax.Core.Settings;
using Module = Autofac.Module;

namespace Wax.Core
Expand All @@ -19,15 +22,15 @@ public class ApplicationModule : Module
{
private readonly ILogger _logger;
private readonly ICurrentUser _currentUser;
private readonly string _connectionString;
private readonly IConfiguration _configuration;
private readonly Assembly[] _assemblies;

public ApplicationModule(ILogger logger, ICurrentUser currentUser, string connectionString,
public ApplicationModule(ILogger logger, ICurrentUser currentUser, IConfiguration configuration,
params Assembly[] assemblies)
{
_logger = logger;
_currentUser = currentUser;
_connectionString = connectionString;
_configuration = configuration;

_assemblies = (assemblies ?? Array.Empty<Assembly>())
.Concat(new[] { typeof(ApplicationModule).Assembly })
Expand All @@ -44,6 +47,19 @@ protected override void Load(ContainerBuilder builder)
RegisterMediator(builder);
RegisterValidator(builder);
}

private void RegisterSettings(ContainerBuilder builder)
{
builder.RegisterInstance(_configuration)
.As<IConfiguration>()
.SingleInstance();

var settingTypes = _assemblies.SelectMany(a => a.GetTypes())
.Where(t => t.IsClass && typeof(IConfigurationSetting).IsAssignableFrom(t))
.ToArray();

builder.RegisterTypes(settingTypes).AsSelf().SingleInstance();
}

private void RegisterAutoMapper(ContainerBuilder builder)
{
Expand All @@ -70,7 +86,9 @@ private void RegisterDatabase(ContainerBuilder builder)
{
builder.Register(c =>
{
if (!string.IsNullOrEmpty(_connectionString))
var connectionString = _configuration.GetConnectionString("Default");

if (!string.IsNullOrEmpty(connectionString))
{
//Select your database provider
}
Expand All @@ -83,10 +101,10 @@ private void RegisterDatabase(ContainerBuilder builder)
}).AsSelf().As<DbContext>()
.InstancePerLifetimeScope();

builder.RegisterGeneric(typeof(EfCoreBasicRepository<>))
builder.RegisterGeneric(typeof(BasicRepository<>))
.As(typeof(IBasicRepository<>))
.InstancePerLifetimeScope();

builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
}

Expand All @@ -111,6 +129,7 @@ private void RegisterMediator(ContainerBuilder builder)
{
c.UseLogger();
c.UseMessageValidator();
c.UseUnitOfWork();
});

builder.RegisterMediator(mediatorBuilder);
Expand Down
22 changes: 22 additions & 0 deletions src/Wax.Core/Data/ApplicationDbContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : ba
{
}

public bool HasEntitiesChanged { get; private set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseInMemoryDatabase("__wax_database");
Expand All @@ -18,4 +20,24 @@ protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfigurationsFromAssembly(typeof(CustomerEntityTypeConfiguration).Assembly);
}


public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken())
{
var result = base.SaveChangesAsync(cancellationToken);

HasEntitiesChanged = false;

return result;
}

public async Task ChangeEntitiesAsync(bool saveNow = false, CancellationToken cancellationToken = default)
{
HasEntitiesChanged = true;

if (saveNow)
{
await SaveChangesAsync(cancellationToken);
}
}
}
21 changes: 21 additions & 0 deletions src/Wax.Core/Data/IUnitOfWork.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace Wax.Core.Data;

public interface IUnitOfWork
{
Task CommitAsync(CancellationToken cancellationToken = default);
}

public class UnitOfWork : IUnitOfWork
{
private readonly ApplicationDbContext _context;

public UnitOfWork(ApplicationDbContext context)
{
_context = context;
}

public Task CommitAsync(CancellationToken cancellationToken = default)
{
return _context.HasEntitiesChanged ? _context.SaveChangesAsync(cancellationToken) : Task.CompletedTask;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AutoMapper;
using Mediator.Net.Context;
using Mediator.Net.Contracts;
using Wax.Core.Data;
using Wax.Core.Domain.Customers;
using Wax.Core.Domain.Customers.Exceptions;
using Wax.Core.Repositories;
Expand All @@ -11,18 +12,19 @@ namespace Wax.Core.Handlers.CommandHandlers.Customers
public class CreateCustomerCommandHandler : ICommandHandler<CreateCustomerCommand, CreateCustomerResponse>
{
private readonly IMapper _mapper;
private readonly ICustomerRepository _customerRepository;
private readonly IUnitOfWork _unitOfWork;

public CreateCustomerCommandHandler(IMapper mapper, IUnitOfWork unitOfWork)
public CreateCustomerCommandHandler(IMapper mapper,ICustomerRepository customerRepository)
{
_mapper = mapper;
_unitOfWork = unitOfWork;
_customerRepository = customerRepository;
}

public async Task<CreateCustomerResponse> Handle(IReceiveContext<CreateCustomerCommand> context,
CancellationToken cancellationToken)
{
var existing = await _unitOfWork.Customers.FindByNameAsync(context.Message.Name, cancellationToken);
var existing = await _customerRepository.FindByNameAsync(context.Message.Name);

if (existing != null)
{
Expand All @@ -31,8 +33,7 @@ public async Task<CreateCustomerResponse> Handle(IReceiveContext<CreateCustomerC

var customer = _mapper.Map<Customer>(context.Message);

await _unitOfWork.Customers.InsertAsync(customer, cancellationToken).ConfigureAwait(false);
await _unitOfWork.SaveChangesAsync(cancellationToken);
await _customerRepository.InsertAsync(customer);

return new CreateCustomerResponse { CustomerId = customer.Id };
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
using Mediator.Net.Context;
using Mediator.Net.Contracts;
using Wax.Core.Data;
using Wax.Core.Repositories;
using Wax.Messages.Commands.Customers;

namespace Wax.Core.Handlers.CommandHandlers.Customers;

public class DeleteCustomerCommandHandler: ICommandHandler<DeleteCustomerCommand>
{
private readonly IUnitOfWork _unitOfWork;
private readonly ICustomerRepository _customerRepository;

public DeleteCustomerCommandHandler(IUnitOfWork unitOfWork)
public DeleteCustomerCommandHandler(ICustomerRepository customerRepository)
{
_unitOfWork = unitOfWork;
_customerRepository = customerRepository;
}

public async Task Handle(IReceiveContext<DeleteCustomerCommand> context, CancellationToken cancellationToken)
{
var customer = await _unitOfWork.Customers.GetByIdAsync(context.Message.CustomerId, cancellationToken);
var customer = await _customerRepository.GetByIdAsync(context.Message.CustomerId);

await _unitOfWork.Customers.DeleteAsync(customer, cancellationToken);
await _unitOfWork.SaveChangesAsync(cancellationToken);
await _customerRepository.DeleteAsync(customer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,21 @@ namespace Wax.Core.Handlers.CommandHandlers.Customers;
public class UpdateCustomerCommandHandler : ICommandHandler<UpdateCustomerCommand>
{
private readonly IMapper _mapper;
private readonly IUnitOfWork _unitOfWork;
private readonly ICustomerRepository _customerRepository;

public UpdateCustomerCommandHandler(IMapper mapper, IUnitOfWork unitOfWork)
public UpdateCustomerCommandHandler(IMapper mapper, ICustomerRepository customerRepository)
{
_mapper = mapper;
_unitOfWork = unitOfWork;
_customerRepository = customerRepository;
}

public async Task Handle(IReceiveContext<UpdateCustomerCommand> context, CancellationToken cancellationToken)
{
var customer = await _unitOfWork.Customers.GetByIdAsync(context.Message.CustomerId, cancellationToken);
var customer = await _customerRepository.GetByIdAsync(context.Message.CustomerId);

if (customer.Name != context.Message.Name)
{
var existing = await _unitOfWork.Customers.FindByNameAsync(context.Message.Name, cancellationToken);
var existing = await _customerRepository.FindByNameAsync(context.Message.Name);

if (existing != null)
{
Expand All @@ -34,7 +34,6 @@ public async Task Handle(IReceiveContext<UpdateCustomerCommand> context, Cancell

_mapper.Map(context.Message, customer);

await _unitOfWork.Customers.UpdateAsync(customer, cancellationToken).ConfigureAwait(false);
await _unitOfWork.SaveChangesAsync(cancellationToken);
await _customerRepository.UpdateAsync(customer);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using AutoMapper;
using Mediator.Net.Context;
using Mediator.Net.Contracts;
using Wax.Core.Data;
using Wax.Core.Repositories;
using Wax.Messages.Dtos.Customers;
using Wax.Messages.Requests.Customers;
Expand All @@ -10,18 +11,18 @@ namespace Wax.Core.Handlers.RequestHandlers.Customers;
public class GetCustomerRequestHandler : IRequestHandler<GetCustomerRequest, GetCustomerResponse>
{
private readonly IMapper _mapper;
private readonly IUnitOfWork _unitOfWork;
private readonly ICustomerRepository _customerRepository;

public GetCustomerRequestHandler(IMapper mapper, IUnitOfWork unitOfWork)
public GetCustomerRequestHandler(IMapper mapper, ICustomerRepository customerRepository)
{
_mapper = mapper;
_unitOfWork = unitOfWork;
_customerRepository = customerRepository;
}

public async Task<GetCustomerResponse> Handle(IReceiveContext<GetCustomerRequest> context,
CancellationToken cancellationToken)
{
var customer = await _unitOfWork.Customers.GetByIdAsync(context.Message.CustomerId, cancellationToken);
var customer = await _customerRepository.GetByIdAsync(context.Message.CustomerId);

return new GetCustomerResponse
{
Expand Down
23 changes: 23 additions & 0 deletions src/Wax.Core/Middlewares/UnitOfWorks/UnitOfWorkMiddleware.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Mediator.Net;
using Mediator.Net.Context;
using Mediator.Net.Contracts;
using Mediator.Net.Pipeline;
using Wax.Core.Data;

namespace Wax.Core.Middlewares.UnitOfWorks;

public static class UnitOfWorkMiddleware
{
public static void UseUnitOfWork<TContext>(this IPipeConfigurator<TContext> configurator)
where TContext : IContext<IMessage>
{
if (configurator.DependencyScope == null)
{
throw new DependencyScopeNotConfiguredException("IDependencyScope is not configured.");
}

var uow = configurator.DependencyScope.Resolve<IUnitOfWork>();

configurator.AddPipeSpecification(new UnitOfWorkSpecification<TContext>(uow));
}
}
46 changes: 46 additions & 0 deletions src/Wax.Core/Middlewares/UnitOfWorks/UnitOfWorkSpecification.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System.Runtime.ExceptionServices;
using Mediator.Net.Context;
using Mediator.Net.Contracts;
using Mediator.Net.Pipeline;
using Wax.Core.Data;

namespace Wax.Core.Middlewares.UnitOfWorks;

public class UnitOfWorkSpecification<TContext> : IPipeSpecification<TContext>
where TContext : IContext<IMessage>
{
private readonly IUnitOfWork _unitOfWork;

public UnitOfWorkSpecification(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
}

public bool ShouldExecute(TContext context, CancellationToken cancellationToken)
{
return context.Message is ICommand or IEvent;
}

public Task BeforeExecute(TContext context, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

public Task Execute(TContext context, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}

public Task AfterExecute(TContext context, CancellationToken cancellationToken)
{
return ShouldExecute(context, cancellationToken)
? _unitOfWork.CommitAsync(cancellationToken)
: Task.CompletedTask;
}

public Task OnException(Exception ex, TContext context)
{
ExceptionDispatchInfo.Capture(ex).Throw();
return Task.CompletedTask;
}
}
Loading

0 comments on commit e4459de

Please sign in to comment.