Skip to content

Commit

Permalink
refactor: use records for dto, remove automapper
Browse files Browse the repository at this point in the history
  • Loading branch information
nadirbad committed Mar 15, 2024
1 parent f359aef commit c4ce144
Show file tree
Hide file tree
Showing 27 changed files with 131 additions and 376 deletions.
3 changes: 1 addition & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
<PackageVersion Include="ErrorOr" Version="1.6.0" />
<PackageVersion Include="FluentValidation" Version="11.9.0" />
<PackageVersion Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageVersion Include="MediatR" Version="12.2.0" />
<PackageVersion Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.0" />
<PackageVersion Include="MediatR" Version="12.2.0" />
<!-- Analyzers -->
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- Tests -->
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ This project repository is created based on [Clean Architecture solution templat
- [ASP.NET API with .NET 8](https://docs.microsoft.com/en-us/aspnet/core/?view=aspnetcore-8.0)
- CQRS with [MediatR](https://github.com/jbogard/MediatR)
- [FluentValidation](https://fluentvalidation.net/)
- [AutoMapper](https://automapper.org/)
- [Entity Framework Core 8](https://docs.microsoft.com/en-us/ef/core/)
- [NUnit](https://nunit.org/), [FluentAssertions](https://fluentassertions.com/), [Moq](https://github.com/moq)
- [xUnit](https://xunit.net/), [FluentAssertions](https://fluentassertions.com/), [Moq](https://github.com/moq)

Afterwards, the projects and architecture is refactored towards the Vertical slice architecture style.

Expand Down
6 changes: 6 additions & 0 deletions src/Application/ApiPaths.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Application;

internal static class ApiPaths
{
internal const string Root = "api";
}
1 change: 0 additions & 1 deletion src/Application/Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" />
<PackageReference Include="CsvHelper" />
<PackageReference Include="ErrorOr" />
<PackageReference Include="FluentValidation" />
Expand Down
11 changes: 0 additions & 11 deletions src/Application/Common/Mappings/IMapFrom.cs

This file was deleted.

12 changes: 1 addition & 11 deletions src/Application/Common/Mappings/MappingExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
using AutoMapper;
using AutoMapper.QueryableExtensions;

using Microsoft.EntityFrameworkCore;

using VerticalSliceArchitecture.Application.Common.Models;
using VerticalSliceArchitecture.Application.Common.Models;

namespace VerticalSliceArchitecture.Application.Common.Mappings;

Expand All @@ -13,9 +8,4 @@ public static Task<PaginatedList<TDestination>> PaginatedListAsync<TDestination>
{
return PaginatedList<TDestination>.CreateAsync(queryable, pageNumber, pageSize);
}

public static Task<List<TDestination>> ProjectToListAsync<TDestination>(this IQueryable queryable, IConfigurationProvider configuration)
{
return queryable.ProjectTo<TDestination>(configuration).ToListAsync();
}
}
31 changes: 0 additions & 31 deletions src/Application/Common/Mappings/MappingProfile.cs

This file was deleted.

1 change: 0 additions & 1 deletion src/Application/ConfigureServices.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddAutoMapper(typeof(DependencyInjection).Assembly);
services.AddValidatorsFromAssembly(typeof(DependencyInjection).Assembly);

services.AddMediatR(options =>
Expand Down
17 changes: 1 addition & 16 deletions src/Application/Domain/Todos/TodoItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,6 @@ public bool Done
public List<DomainEvent> DomainEvents { get; } = new List<DomainEvent>();
}

public class TodoItemCompletedEvent : DomainEvent
{
public TodoItemCompletedEvent(TodoItem item)
{
Item = item;
}

public TodoItem Item { get; }
}

public enum PriorityLevel
{
None = 0,
Expand All @@ -55,9 +45,4 @@ public enum PriorityLevel
High = 3,
}

public class TodoItemRecord : IMapFrom<TodoItem>
{
public string? Title { get; set; }

public bool Done { get; set; }
}
public record TodoItemRecord(string? Title, bool Done);
8 changes: 8 additions & 0 deletions src/Application/Domain/Todos/TodoItemCompletedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using VerticalSliceArchitecture.Application.Common;

namespace VerticalSliceArchitecture.Application.Domain.Todos;

internal sealed class TodoItemCompletedEvent(TodoItem item) : DomainEvent
{
public TodoItem Item { get; } = item;
}
8 changes: 8 additions & 0 deletions src/Application/Domain/Todos/TodoItemCreatedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using VerticalSliceArchitecture.Application.Common;

namespace VerticalSliceArchitecture.Application.Domain.Todos;

internal sealed class TodoItemCreatedEvent(TodoItem item) : DomainEvent
{
public TodoItem Item { get; } = item;
}
8 changes: 8 additions & 0 deletions src/Application/Domain/Todos/TodoItemDeletedEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using VerticalSliceArchitecture.Application.Common;

namespace VerticalSliceArchitecture.Application.Domain.Todos;

internal sealed class TodoItemDeletedEvent(TodoItem item) : DomainEvent
{
public TodoItem Item { get; } = item;
}
28 changes: 4 additions & 24 deletions src/Application/Features/TodoItems/CreateTodoItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,9 @@ public async Task<ActionResult<int>> Create(CreateTodoItemCommand command)
}
}

public class CreateTodoItemCommand : IRequest<int>
{
public int ListId { get; set; }

public string? Title { get; set; }
}
public record CreateTodoItemCommand(int ListId, string? Title) : IRequest<int>;

public class CreateTodoItemCommandValidator : AbstractValidator<CreateTodoItemCommand>
internal sealed class CreateTodoItemCommandValidator : AbstractValidator<CreateTodoItemCommand>
{
public CreateTodoItemCommandValidator()
{
Expand All @@ -36,14 +31,9 @@ public CreateTodoItemCommandValidator()
}
}

internal sealed class CreateTodoItemCommandHandler : IRequestHandler<CreateTodoItemCommand, int>
internal sealed class CreateTodoItemCommandHandler(ApplicationDbContext context) : IRequestHandler<CreateTodoItemCommand, int>
{
private readonly ApplicationDbContext _context;

public CreateTodoItemCommandHandler(ApplicationDbContext context)
{
_context = context;
}
private readonly ApplicationDbContext _context = context;

public async Task<int> Handle(CreateTodoItemCommand request, CancellationToken cancellationToken)
{
Expand All @@ -62,14 +52,4 @@ public async Task<int> Handle(CreateTodoItemCommand request, CancellationToken c

return entity.Id;
}
}

internal sealed class TodoItemCreatedEvent : DomainEvent
{
public TodoItemCreatedEvent(TodoItem item)
{
Item = item;
}

public TodoItem Item { get; }
}
26 changes: 4 additions & 22 deletions src/Application/Features/TodoItems/DeleteTodoItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,17 @@ public class DeleteTodoItemController : ApiControllerBase
[HttpDelete("/api/todo-items/{id}")]
public async Task<ActionResult> Delete(int id)
{
await Mediator.Send(new DeleteTodoItemCommand { Id = id });
await Mediator.Send(new DeleteTodoItemCommand(id));

return NoContent();
}
}

public class DeleteTodoItemCommand : IRequest
{
public int Id { get; set; }
}
public record DeleteTodoItemCommand(int Id) : IRequest;

internal sealed class DeleteTodoItemCommandHandler : IRequestHandler<DeleteTodoItemCommand>
internal sealed class DeleteTodoItemCommandHandler(ApplicationDbContext context) : IRequestHandler<DeleteTodoItemCommand>
{
private readonly ApplicationDbContext _context;

public DeleteTodoItemCommandHandler(ApplicationDbContext context)
{
_context = context;
}
private readonly ApplicationDbContext _context = context;

public async Task Handle(DeleteTodoItemCommand request, CancellationToken cancellationToken)
{
Expand All @@ -44,14 +36,4 @@ public async Task Handle(DeleteTodoItemCommand request, CancellationToken cancel

await _context.SaveChangesAsync(cancellationToken);
}
}

internal class TodoItemDeletedEvent : DomainEvent
{
public TodoItemDeletedEvent(TodoItem item)
{
Item = item;
}

public TodoItem Item { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,9 @@

namespace VerticalSliceArchitecture.Application.Features.TodoItems.EventHandlers;

public class TodoItemCompletedEventHandler : INotificationHandler<DomainEventNotification<TodoItemCompletedEvent>>
internal sealed class TodoItemCompletedEventHandler(ILogger<TodoItemCompletedEventHandler> logger) : INotificationHandler<DomainEventNotification<TodoItemCompletedEvent>>
{
private readonly ILogger<TodoItemCompletedEventHandler> _logger;

public TodoItemCompletedEventHandler(ILogger<TodoItemCompletedEventHandler> logger)
{
_logger = logger;
}
private readonly ILogger<TodoItemCompletedEventHandler> _logger = logger;

public Task Handle(DomainEventNotification<TodoItemCompletedEvent> notification, CancellationToken cancellationToken)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,13 @@
using Microsoft.Extensions.Logging;

using VerticalSliceArchitecture.Application.Common.Models;
using VerticalSliceArchitecture.Application.Domain.Todos;

namespace VerticalSliceArchitecture.Application.Features.TodoItems.EventHandlers;

internal sealed class TodoItemCreatedEventHandler : INotificationHandler<DomainEventNotification<TodoItemCreatedEvent>>
internal sealed class TodoItemCreatedEventHandler(ILogger<TodoItemCreatedEventHandler> logger) : INotificationHandler<DomainEventNotification<TodoItemCreatedEvent>>
{
private readonly ILogger<TodoItemCreatedEventHandler> _logger;

public TodoItemCreatedEventHandler(ILogger<TodoItemCreatedEventHandler> logger)
{
_logger = logger;
}
private readonly ILogger<TodoItemCreatedEventHandler> _logger = logger;

public Task Handle(DomainEventNotification<TodoItemCreatedEvent> notification, CancellationToken cancellationToken)
{
Expand Down
49 changes: 14 additions & 35 deletions src/Application/Features/TodoItems/GetTodoItemsWithPagination.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
using AutoMapper;
using AutoMapper.QueryableExtensions;

using FluentValidation;
using FluentValidation;

using MediatR;

Expand All @@ -18,31 +15,17 @@ namespace VerticalSliceArchitecture.Application.Features.TodoItems;
public class GetTodoItemsWithPaginationController : ApiControllerBase
{
[HttpGet("/api/todo-items")]
public Task<PaginatedList<TodoItemBriefDto>> GetTodoItemsWithPagination([FromQuery] GetTodoItemsWithPaginationQuery query)
public Task<PaginatedList<TodoItemBriefResponse>> GetTodoItemsWithPagination([FromQuery] GetTodoItemsWithPaginationQuery query)
{
return Mediator.Send(query);
}
}

public class TodoItemBriefDto : IMapFrom<TodoItem>
{
public int Id { get; set; }

public int ListId { get; set; }

public string? Title { get; set; }

public bool Done { get; set; }
}
public record TodoItemBriefResponse(int Id, int ListId, string? Title, bool Done);

public class GetTodoItemsWithPaginationQuery : IRequest<PaginatedList<TodoItemBriefDto>>
{
public int ListId { get; set; }
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
}
public record GetTodoItemsWithPaginationQuery(int ListId, int PageNumber = 1, int PageSize = 10) : IRequest<PaginatedList<TodoItemBriefResponse>>;

public class GetTodoItemsWithPaginationQueryValidator : AbstractValidator<GetTodoItemsWithPaginationQuery>
internal sealed class GetTodoItemsWithPaginationQueryValidator : AbstractValidator<GetTodoItemsWithPaginationQuery>
{
public GetTodoItemsWithPaginationQueryValidator()
{
Expand All @@ -57,23 +40,19 @@ public GetTodoItemsWithPaginationQueryValidator()
}
}

internal sealed class GetTodoItemsWithPaginationQueryHandler : IRequestHandler<GetTodoItemsWithPaginationQuery, PaginatedList<TodoItemBriefDto>>
internal sealed class GetTodoItemsWithPaginationQueryHandler(ApplicationDbContext context) : IRequestHandler<GetTodoItemsWithPaginationQuery, PaginatedList<TodoItemBriefResponse>>
{
private readonly ApplicationDbContext _context;
private readonly IMapper _mapper;

public GetTodoItemsWithPaginationQueryHandler(ApplicationDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
private readonly ApplicationDbContext _context = context;

public Task<PaginatedList<TodoItemBriefDto>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken)
public Task<PaginatedList<TodoItemBriefResponse>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken)
{
return _context.TodoItems
.Where(x => x.ListId == request.ListId)
.OrderBy(x => x.Title)
.ProjectTo<TodoItemBriefDto>(_mapper.ConfigurationProvider)
.Where(item => item.ListId == request.ListId)
.OrderBy(item => item.Title)
.Select(item => ToDto(item))
.PaginatedListAsync(request.PageNumber, request.PageSize);
}

private static TodoItemBriefResponse ToDto(TodoItem todoItem) =>
new(todoItem.Id, todoItem.ListId, todoItem.Title, todoItem.Done);
}
Loading

0 comments on commit c4ce144

Please sign in to comment.