Skip to content

Commit

Permalink
Product Service: switching to MediatR is super straightforward
Browse files Browse the repository at this point in the history
  • Loading branch information
phongnguyend committed May 25, 2023
1 parent cedb08e commit c312a24
Show file tree
Hide file tree
Showing 13 changed files with 67 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="MediatR" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="7.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.1" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
using ClassifiedAds.Application;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.Domain.Repositories;
using ClassifiedAds.Infrastructure.Identity;
using ClassifiedAds.Services.Product.Entities;
using MediatR;
using System;
using System.Threading;
using System.Threading.Tasks;

namespace ClassifiedAds.Services.Product.Commands;

public class AddAuditLogEntryCommand : ICommand
public class AddAuditLogEntryCommand : IRequest
{
public AuditLogEntry AuditLogEntry { get; set; }
}

public class AddAuditLogEntryCommandHandler : ICommandHandler<AddAuditLogEntryCommand>
public class AddAuditLogEntryCommandHandler : IRequestHandler<AddAuditLogEntryCommand>
{
private readonly ICurrentUser _currentUser;
private readonly IRepository<AuditLogEntry, Guid> _auditLogRepository;
Expand All @@ -30,7 +29,7 @@ public class AddAuditLogEntryCommandHandler : ICommandHandler<AddAuditLogEntryCo
_outboxEventRepository = outboxEventRepository;
}

public async Task HandleAsync(AddAuditLogEntryCommand command, CancellationToken cancellationToken = default)
public async Task Handle(AddAuditLogEntryCommand command, CancellationToken cancellationToken)
{
var auditLog = new AuditLogEntry
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using ClassifiedAds.Application;
using MediatR;
using System.Threading;
using System.Threading.Tasks;

namespace ClassifiedAds.Services.Product.Commands;

public class AddUpdateProductCommand : ICommand
public class AddUpdateProductCommand : IRequest
{
public Entities.Product Product { get; set; }
}

public class AddUpdateProductCommandHandler : ICommandHandler<AddUpdateProductCommand>
public class AddUpdateProductCommandHandler : IRequestHandler<AddUpdateProductCommand>
{
private readonly ICrudService<Entities.Product> _productService;

Expand All @@ -18,7 +19,7 @@ public AddUpdateProductCommandHandler(ICrudService<Entities.Product> productServ
_productService = productService;
}

public async Task HandleAsync(AddUpdateProductCommand command, CancellationToken cancellationToken = default)
public async Task Handle(AddUpdateProductCommand command, CancellationToken cancellationToken = default)
{
await _productService.AddOrUpdateAsync(command.Product);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using ClassifiedAds.Application;
using MediatR;
using System.Threading;
using System.Threading.Tasks;

namespace ClassifiedAds.Services.Product.Commands;

public class DeleteProductCommand : ICommand
public class DeleteProductCommand : IRequest
{
public Entities.Product Product { get; set; }
}

public class DeleteProductCommandHandler : ICommandHandler<DeleteProductCommand>
public class DeleteProductCommandHandler : IRequestHandler<DeleteProductCommand>
{
private readonly ICrudService<Entities.Product> _productService;

Expand All @@ -18,7 +19,7 @@ public DeleteProductCommandHandler(ICrudService<Entities.Product> productService
_productService = productService;
}

public async Task HandleAsync(DeleteProductCommand command, CancellationToken cancellationToken = default)
public async Task Handle(DeleteProductCommand command, CancellationToken cancellationToken = default)
{
await _productService.DeleteAsync(command.Product);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using ClassifiedAds.Application;
using ClassifiedAds.CrossCuttingConcerns.Csv;
using ClassifiedAds.CrossCuttingConcerns.Csv;
using ClassifiedAds.CrossCuttingConcerns.HtmlGenerator;
using ClassifiedAds.CrossCuttingConcerns.PdfConverter;
using ClassifiedAds.Services.Product.Authorization;
Expand All @@ -8,6 +7,7 @@
using ClassifiedAds.Services.Product.Models;
using ClassifiedAds.Services.Product.Queries;
using ClassifiedAds.Services.Product.RateLimiterPolicies;
using MediatR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -30,14 +30,14 @@ namespace ClassifiedAds.Services.Product.Controllers;
[ApiController]
public class ProductsController : ControllerBase
{
private readonly Dispatcher _dispatcher;
private readonly IMediator _dispatcher;
private readonly ILogger _logger;
private readonly IHtmlGenerator _htmlGenerator;
private readonly IPdfConverter _pdfConverter;
private readonly ICsvWriter<ProductModel> _productCsvWriter;
private readonly ICsvReader<ProductModel> _productCsvReader;

public ProductsController(Dispatcher dispatcher,
public ProductsController(IMediator dispatcher,
ILogger<ProductsController> logger,
IHtmlGenerator htmlGenerator,
IPdfConverter pdfConverter,
Expand All @@ -57,7 +57,7 @@ public class ProductsController : ControllerBase
public async Task<ActionResult<IEnumerable<Entities.Product>>> Get()
{
_logger.LogInformation("Getting all products");
var products = await _dispatcher.DispatchAsync(new GetProductsQuery());
var products = await _dispatcher.Send(new GetProductsQuery());
var model = products.ToModels();
return Ok(model);
}
Expand All @@ -68,7 +68,7 @@ public async Task<ActionResult<IEnumerable<Entities.Product>>> Get()
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult<Entities.Product>> Get(Guid id)
{
var product = await _dispatcher.DispatchAsync(new GetProductQuery { Id = id, ThrowNotFoundIfNull = true });
var product = await _dispatcher.Send(new GetProductQuery { Id = id, ThrowNotFoundIfNull = true });
var model = product.ToModel();
return Ok(model);
}
Expand All @@ -80,7 +80,7 @@ public async Task<ActionResult<Entities.Product>> Get(Guid id)
public async Task<ActionResult<Entities.Product>> Post([FromBody] ProductModel model)
{
var product = model.ToEntity();
await _dispatcher.DispatchAsync(new AddUpdateProductCommand { Product = product });
await _dispatcher.Send(new AddUpdateProductCommand { Product = product });
model = product.ToModel();
return Created($"/api/products/{model.Id}", model);
}
Expand All @@ -92,13 +92,13 @@ public async Task<ActionResult<Entities.Product>> Post([FromBody] ProductModel m
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> Put(Guid id, [FromBody] ProductModel model)
{
var product = await _dispatcher.DispatchAsync(new GetProductQuery { Id = id, ThrowNotFoundIfNull = true });
var product = await _dispatcher.Send(new GetProductQuery { Id = id, ThrowNotFoundIfNull = true });

product.Code = model.Code;
product.Name = model.Name;
product.Description = model.Description;

await _dispatcher.DispatchAsync(new AddUpdateProductCommand { Product = product });
await _dispatcher.Send(new AddUpdateProductCommand { Product = product });

model = product.ToModel();

Expand All @@ -111,9 +111,9 @@ public async Task<ActionResult> Put(Guid id, [FromBody] ProductModel model)
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<ActionResult> Delete(Guid id)
{
var product = await _dispatcher.DispatchAsync(new GetProductQuery { Id = id, ThrowNotFoundIfNull = true });
var product = await _dispatcher.Send(new GetProductQuery { Id = id, ThrowNotFoundIfNull = true });

await _dispatcher.DispatchAsync(new DeleteProductCommand { Product = product });
await _dispatcher.Send(new DeleteProductCommand { Product = product });

return Ok();
}
Expand All @@ -122,7 +122,7 @@ public async Task<ActionResult> Delete(Guid id)
[HttpGet("{id}/auditlogs")]
public async Task<ActionResult<IEnumerable<AuditLogEntryDTO>>> GetAuditLogs(Guid id)
{
var logs = await _dispatcher.DispatchAsync(new GetAuditEntriesQuery { ObjectId = id.ToString() });
var logs = await _dispatcher.Send(new GetAuditEntriesQuery { ObjectId = id.ToString() });

List<dynamic> entries = new List<dynamic>();
ProductModel previous = null;
Expand Down Expand Up @@ -156,7 +156,7 @@ public async Task<ActionResult<IEnumerable<AuditLogEntryDTO>>> GetAuditLogs(Guid
[HttpGet("exportaspdf")]
public async Task<IActionResult> ExportAsPdf()
{
var products = await _dispatcher.DispatchAsync(new GetProductsQuery());
var products = await _dispatcher.Send(new GetProductsQuery());
var model = products.ToModels();

var template = Path.Combine(Environment.CurrentDirectory, $"Templates/ProductList.cshtml");
Expand All @@ -169,7 +169,7 @@ public async Task<IActionResult> ExportAsPdf()
[HttpGet("exportascsv")]
public async Task<IActionResult> ExportAsCsv()
{
var products = await _dispatcher.DispatchAsync(new GetProductsQuery());
var products = await _dispatcher.Send(new GetProductsQuery());
var model = products.ToModels();
using var stream = new MemoryStream();
_productCsvWriter.Write(model, stream);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
using ClassifiedAds.Application;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.Domain.Events;
using ClassifiedAds.Domain.Repositories;
using ClassifiedAds.Infrastructure.Identity;
using ClassifiedAds.Services.Product.Commands;
using ClassifiedAds.Services.Product.Entities;
using MediatR;
using System;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -13,11 +13,11 @@ namespace ClassifiedAds.Services.Product.EventHandlers;

public class ProductCreatedEventHandler : IDomainEventHandler<EntityCreatedEvent<Entities.Product>>
{
private readonly Dispatcher _dispatcher;
private readonly IMediator _dispatcher;
private readonly ICurrentUser _currentUser;
private readonly IRepository<OutboxEvent, long> _outboxEventRepository;

public ProductCreatedEventHandler(Dispatcher dispatcher,
public ProductCreatedEventHandler(IMediator dispatcher,
ICurrentUser currentUser,
IRepository<OutboxEvent, long> outboxEventRepository)
{
Expand All @@ -28,7 +28,7 @@ public class ProductCreatedEventHandler : IDomainEventHandler<EntityCreatedEvent

public async Task HandleAsync(EntityCreatedEvent<Entities.Product> domainEvent, CancellationToken cancellationToken = default)
{
await _dispatcher.DispatchAsync(new AddAuditLogEntryCommand
await _dispatcher.Send(new AddAuditLogEntryCommand
{
AuditLogEntry = new AuditLogEntry
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
using ClassifiedAds.Application;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.Domain.Events;
using ClassifiedAds.Domain.Repositories;
using ClassifiedAds.Infrastructure.Identity;
using ClassifiedAds.Services.Product.Commands;
using ClassifiedAds.Services.Product.Entities;
using MediatR;
using System.Threading;
using System.Threading.Tasks;

namespace ClassifiedAds.Services.Product.EventHandlers;

public class ProductDeletedEventHandler : IDomainEventHandler<EntityDeletedEvent<Entities.Product>>
{
private readonly Dispatcher _dispatcher;
private readonly IMediator _dispatcher;
private readonly ICurrentUser _currentUser;
private readonly IRepository<OutboxEvent, long> _outboxEventRepository;

public ProductDeletedEventHandler(Dispatcher dispatcher,
public ProductDeletedEventHandler(IMediator dispatcher,
ICurrentUser currentUser,
IRepository<OutboxEvent, long> outboxEventRepository)
{
Expand All @@ -27,7 +27,7 @@ public class ProductDeletedEventHandler : IDomainEventHandler<EntityDeletedEvent

public async Task HandleAsync(EntityDeletedEvent<Entities.Product> domainEvent, CancellationToken cancellationToken = default)
{
await _dispatcher.DispatchAsync(new AddAuditLogEntryCommand
await _dispatcher.Send(new AddAuditLogEntryCommand
{
AuditLogEntry = new AuditLogEntry
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
using ClassifiedAds.Application;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.CrossCuttingConcerns.ExtensionMethods;
using ClassifiedAds.Domain.Events;
using ClassifiedAds.Domain.Repositories;
using ClassifiedAds.Infrastructure.Identity;
using ClassifiedAds.Services.Product.Commands;
using ClassifiedAds.Services.Product.Entities;
using MediatR;
using System.Threading;
using System.Threading.Tasks;

namespace ClassifiedAds.Services.Product.EventHandlers;

public class ProductUpdatedEventHandler : IDomainEventHandler<EntityUpdatedEvent<Entities.Product>>
{
private readonly Dispatcher _dispatcher;
private readonly IMediator _dispatcher;
private readonly ICurrentUser _currentUser;
private readonly IRepository<OutboxEvent, long> _outboxEventRepository;

public ProductUpdatedEventHandler(Dispatcher dispatcher,
public ProductUpdatedEventHandler(IMediator dispatcher,
ICurrentUser currentUser,
IRepository<OutboxEvent, long> outboxEventRepository)
{
Expand All @@ -27,7 +27,7 @@ public class ProductUpdatedEventHandler : IDomainEventHandler<EntityUpdatedEvent

public async Task HandleAsync(EntityUpdatedEvent<Entities.Product> domainEvent, CancellationToken cancellationToken = default)
{
await _dispatcher.DispatchAsync(new AddAuditLogEntryCommand
await _dispatcher.Send(new AddAuditLogEntryCommand
{
AuditLogEntry = new AuditLogEntry
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static IServiceCollection AddProductModule(this IServiceCollection servic

DomainEvents.RegisterHandlers(Assembly.GetExecutingAssembly(), services);

services.AddMessageHandlers(Assembly.GetExecutingAssembly());
services.AddMediatR(config => config.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));

services.AddAuthorizationPolicies(Assembly.GetExecutingAssembly(), AuthorizationPolicyNames.GetPolicyNames());

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using ClassifiedAds.Application;
using ClassifiedAds.Services.Product.DTOs;
using ClassifiedAds.Services.Product.DTOs;
using ClassifiedAds.Services.Product.Entities;
using ClassifiedAds.Services.Product.Repositories;
using MediatR;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
Expand All @@ -11,22 +11,22 @@

namespace ClassifiedAds.Services.Product.Queries;

public class GetAuditEntriesQuery : AuditLogEntryQueryOptions, IQuery<List<AuditLogEntryDTO>>
public class GetAuditEntriesQuery : AuditLogEntryQueryOptions, IRequest<List<AuditLogEntryDTO>>
{
}

public class GetAuditEntriesQueryHandler : IQueryHandler<GetAuditEntriesQuery, List<AuditLogEntryDTO>>
public class GetAuditEntriesQueryHandler : IRequestHandler<GetAuditEntriesQuery, List<AuditLogEntryDTO>>
{
private readonly ProductDbContext _dbContext;
private readonly Dispatcher _dispatcher;
private readonly IMediator _dispatcher;

public GetAuditEntriesQueryHandler(ProductDbContext dbContext, Dispatcher dispatcher)
public GetAuditEntriesQueryHandler(ProductDbContext dbContext, IMediator dispatcher)
{
_dbContext = dbContext;
_dispatcher = dispatcher;
}

public async Task<List<AuditLogEntryDTO>> HandleAsync(GetAuditEntriesQuery queryOptions, CancellationToken cancellationToken = default)
public async Task<List<AuditLogEntryDTO>> Handle(GetAuditEntriesQuery queryOptions, CancellationToken cancellationToken = default)
{
var query = _dbContext.Set<AuditLogEntry>() as IQueryable<AuditLogEntry>;

Expand All @@ -46,7 +46,7 @@ public async Task<List<AuditLogEntryDTO>> HandleAsync(GetAuditEntriesQuery query
}

var auditLogs = await query.ToListAsync();
var users = await _dispatcher.DispatchAsync(new GetUsersQuery(), cancellationToken);
var users = await _dispatcher.Send(new GetUsersQuery(), cancellationToken);

var rs = auditLogs.Join(users, x => x.UserId, y => y.Id,
(x, y) => new AuditLogEntryDTO
Expand Down
Loading

0 comments on commit c312a24

Please sign in to comment.