Style: C# 12 Primary constructor

This commit is contained in:
Kamigen
2024-03-30 20:59:17 -04:00
parent 786c65410d
commit 8f58311283
50 changed files with 267 additions and 449 deletions

View File

@@ -5,19 +5,12 @@ using Hutopy.Application.Common.Security;
namespace Hutopy.Application.Common.Behaviours;
public class AuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
public class AuthorizationBehaviour<TRequest, TResponse>(
IUser user,
IIdentityService identityService)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IUser _user;
private readonly IIdentityService _identityService;
public AuthorizationBehaviour(
IUser user,
IIdentityService identityService)
{
_user = user;
_identityService = identityService;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
var authorizeAttributes = request.GetType().GetCustomAttributes<AuthorizeAttribute>();
@@ -25,7 +18,7 @@ public class AuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRe
if (authorizeAttributes.Any())
{
// Must be authenticated user
if (_user.Id == null)
if (user.Id == null)
{
throw new UnauthorizedAccessException();
}
@@ -41,7 +34,7 @@ public class AuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRe
{
foreach (var role in roles)
{
var isInRole = await _identityService.IsInRoleAsync(_user.Id, role.Trim());
var isInRole = await identityService.IsInRoleAsync(user.Id, role.Trim());
if (isInRole)
{
authorized = true;
@@ -63,7 +56,7 @@ public class AuthorizationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRe
{
foreach (var policy in authorizeAttributesWithPolicies.Select(a => a.Policy))
{
var authorized = await _identityService.AuthorizeAsync(_user.Id, policy);
var authorized = await identityService.AuthorizeAsync(user.Id, policy);
if (!authorized)
{

View File

@@ -4,28 +4,24 @@ using Microsoft.Extensions.Logging;
namespace Hutopy.Application.Common.Behaviours;
public class LoggingBehaviour<TRequest> : IRequestPreProcessor<TRequest> where TRequest : notnull
public class LoggingBehaviour<TRequest>(
ILogger<TRequest> logger,
IUser user,
IIdentityService identityService)
: IRequestPreProcessor<TRequest>
where TRequest : notnull
{
private readonly ILogger _logger;
private readonly IUser _user;
private readonly IIdentityService _identityService;
public LoggingBehaviour(ILogger<TRequest> logger, IUser user, IIdentityService identityService)
{
_logger = logger;
_user = user;
_identityService = identityService;
}
private readonly ILogger _logger = logger;
public async Task Process(TRequest request, CancellationToken cancellationToken)
{
var requestName = typeof(TRequest).Name;
var userId = _user.Id ?? string.Empty;
var userId = user.Id ?? string.Empty;
string? userName = string.Empty;
if (!string.IsNullOrEmpty(userId))
{
userName = await _identityService.GetUserNameAsync(userId);
userName = await identityService.GetUserNameAsync(userId);
}
_logger.LogInformation("Hutopy Request: {Name} {@UserId} {@UserName} {@Request}",

View File

@@ -4,24 +4,14 @@ using Microsoft.Extensions.Logging;
namespace Hutopy.Application.Common.Behaviours;
public class PerformanceBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
public class PerformanceBehaviour<TRequest, TResponse>(
ILogger<TRequest> logger,
IUser user,
IIdentityService identityService)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly Stopwatch _timer;
private readonly ILogger<TRequest> _logger;
private readonly IUser _user;
private readonly IIdentityService _identityService;
public PerformanceBehaviour(
ILogger<TRequest> logger,
IUser user,
IIdentityService identityService)
{
_timer = new Stopwatch();
_logger = logger;
_user = user;
_identityService = identityService;
}
private readonly Stopwatch _timer = new();
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
@@ -33,20 +23,16 @@ public class PerformanceBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequ
var elapsedMilliseconds = _timer.ElapsedMilliseconds;
if (elapsedMilliseconds > 500)
{
var requestName = typeof(TRequest).Name;
var userId = _user.Id ?? string.Empty;
var userName = string.Empty;
if (elapsedMilliseconds <= 500) return response;
if (!string.IsNullOrEmpty(userId))
{
userName = await _identityService.GetUserNameAsync(userId);
}
var requestName = typeof(TRequest).Name;
var userId = user.Id ?? string.Empty;
var userName = string.Empty;
_logger.LogWarning("Hutopy Long Running Request: {Name} ({ElapsedMilliseconds} milliseconds) {@UserId} {@UserName} {@Request}",
requestName, elapsedMilliseconds, userId, userName, request);
}
if (!string.IsNullOrEmpty(userId)) userName = await identityService.GetUserNameAsync(userId);
logger.LogWarning("Hutopy Long Running Request: {Name} ({ElapsedMilliseconds} milliseconds) {@UserId} {@UserName} {@Request}",
requestName, elapsedMilliseconds, userId, userName, request);
return response;
}

View File

@@ -2,15 +2,11 @@
namespace Hutopy.Application.Common.Behaviours;
public class UnhandledExceptionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : notnull
public class UnhandledExceptionBehaviour<TRequest, TResponse>(
ILogger<TRequest> logger)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly ILogger<TRequest> _logger;
public UnhandledExceptionBehaviour(ILogger<TRequest> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
try
@@ -21,7 +17,7 @@ public class UnhandledExceptionBehaviour<TRequest, TResponse> : IPipelineBehavio
{
var requestName = typeof(TRequest).Name;
_logger.LogError(ex, "Hutopy Request: Unhandled Exception for Request {Name} {@Request}", requestName, request);
logger.LogError(ex, "Hutopy Request: Unhandled Exception for Request {Name} {@Request}", requestName, request);
throw;
}

View File

@@ -2,34 +2,27 @@
namespace Hutopy.Application.Common.Behaviours;
public class ValidationBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
public class ValidationBehaviour<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators)
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehaviour(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
if (!validators.Any()) return await next();
var validationResults = await Task.WhenAll(
_validators.Select(v =>
v.ValidateAsync(context, cancellationToken)));
var context = new ValidationContext<TRequest>(request);
var failures = validationResults
.Where(r => r.Errors.Any())
.SelectMany(r => r.Errors)
.ToList();
var validationResults = await Task.WhenAll(
validators.Select(v =>
v.ValidateAsync(context, cancellationToken)));
if (failures.Any())
throw new ValidationException(failures);
}
var failures = validationResults
.Where(r => r.Errors.Any())
.SelectMany(r => r.Errors)
.ToList();
if (failures.Count != 0) throw new ValidationException(failures);
return await next();
}
}

View File

@@ -2,14 +2,9 @@
namespace Hutopy.Application.Common.Exceptions;
public class ValidationException : Exception
public class ValidationException()
: Exception("One or more validation failures have occurred.")
{
public ValidationException()
: base("One or more validation failures have occurred.")
{
Errors = new Dictionary<string, string[]>();
}
public ValidationException(IEnumerable<ValidationFailure> failures)
: this()
{
@@ -18,5 +13,5 @@ public class ValidationException : Exception
.ToDictionary(failureGroup => failureGroup.Key, failureGroup => failureGroup.ToArray());
}
public IDictionary<string, string[]> Errors { get; }
public IDictionary<string, string[]> Errors { get; } = new Dictionary<string, string[]>();
}

View File

@@ -1,19 +1,15 @@
namespace Hutopy.Application.Common.Models;
public class PaginatedList<T>
public class PaginatedList<T>(
IReadOnlyCollection<T> items,
int count,
int pageNumber,
int pageSize)
{
public IReadOnlyCollection<T> Items { get; }
public int PageNumber { get; }
public int TotalPages { get; }
public int TotalCount { get; }
public PaginatedList(IReadOnlyCollection<T> items, int count, int pageNumber, int pageSize)
{
PageNumber = pageNumber;
TotalPages = (int)Math.Ceiling(count / (double)pageSize);
TotalCount = count;
Items = items;
}
public IReadOnlyCollection<T> Items { get; } = items;
public int PageNumber { get; } = pageNumber;
public int TotalPages { get; } = (int)Math.Ceiling(count / (double)pageSize);
public int TotalCount { get; } = count;
public bool HasPreviousPage => PageNumber > 1;

View File

@@ -1,16 +1,12 @@
namespace Hutopy.Application.Common.Models;
public class Result
public class Result(
bool succeeded,
IEnumerable<string> errors)
{
internal Result(bool succeeded, IEnumerable<string> errors)
{
Succeeded = succeeded;
Errors = errors.ToArray();
}
public bool Succeeded { get; init; } = succeeded;
public bool Succeeded { get; init; }
public string[] Errors { get; init; }
public string[] Errors { get; init; } = errors.ToArray();
public static Result Success()
{

View File

@@ -3,7 +3,7 @@
/// <summary>
/// Specifies the class this attribute is applied to requires authorization.
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AuthorizeAttribute : Attribute
{
/// <summary>

View File

@@ -1,6 +1,7 @@
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Extensions.DependencyInjection;
namespace Hutopy.Application;
public static class DependencyInjection
{

View File

@@ -3,7 +3,7 @@ using Hutopy.Domain.Entities;
namespace Hutopy.Application.FutureCreators.Commands;
public record CreateFutureCreatorCommand : IRequest<int>
public abstract record CreateFutureCreatorCommand : IRequest<int>
{
public required string FirstName { get; init; }
public required string LastName { get; init; }
@@ -13,16 +13,10 @@ public record CreateFutureCreatorCommand : IRequest<int>
public required string ReasonToJoin { get; init; }
}
public class CreateFuturCreatorCommandHandler : IRequestHandler<CreateFutureCreatorCommand, int>
public class CreateFutureCreatorCommandHandler(
IApplicationDbContext context)
: IRequestHandler<CreateFutureCreatorCommand, int>
{
private readonly IApplicationDbContext _context;
public CreateFuturCreatorCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<int> Handle(CreateFutureCreatorCommand request, CancellationToken cancellationToken)
{
var entity = new FutureCreator
@@ -35,9 +29,9 @@ public class CreateFuturCreatorCommandHandler : IRequestHandler<CreateFutureCrea
ReasonToJoin = request.ReasonToJoin,
};
_context.FutureCreators.Add(entity);
context.FutureCreators.Add(entity);
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
return entity.Id;
}

View File

@@ -2,7 +2,7 @@
namespace Hutopy.Application.Stripe.Commands;
public record CreateSessionCheckoutCommand : IRequest<string>
public abstract record CreateSessionCheckoutCommand : IRequest<string>
{
public required int Price { get; init; }
@@ -10,21 +10,16 @@ public record CreateSessionCheckoutCommand : IRequest<string>
}
public class CreateSessionCheckoutCommandHandler : IRequestHandler<CreateSessionCheckoutCommand, string>
public class CreateSessionCheckoutCommandHandler(
IApplicationDbContext context,
IStripeService stripeService)
: IRequestHandler<CreateSessionCheckoutCommand, string>
{
private readonly IApplicationDbContext _context;
private readonly IStripeService _stripeService;
public CreateSessionCheckoutCommandHandler(IApplicationDbContext context, IStripeService stripeService)
{
_context = context;
_stripeService = stripeService;
}
private readonly IApplicationDbContext _context = context;
public async Task<string> Handle(CreateSessionCheckoutCommand request, CancellationToken cancellationToken)
{
var stripeSecret = await _stripeService.CreateCheckoutSession(request.Price, request.Currency);
var stripeSecret = await stripeService.CreateCheckoutSession(request.Price, request.Currency);
return stripeSecret;
}

View File

@@ -11,15 +11,10 @@ public record CreateTodoItemCommand : IRequest<int>
public string? Title { get; init; }
}
public class CreateTodoItemCommandHandler : IRequestHandler<CreateTodoItemCommand, int>
public class CreateTodoItemCommandHandler(
IApplicationDbContext context)
: IRequestHandler<CreateTodoItemCommand, int>
{
private readonly IApplicationDbContext _context;
public CreateTodoItemCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<int> Handle(CreateTodoItemCommand request, CancellationToken cancellationToken)
{
var entity = new TodoItem
@@ -31,9 +26,9 @@ public class CreateTodoItemCommandHandler : IRequestHandler<CreateTodoItemComman
entity.AddDomainEvent(new TodoItemCreatedEvent(entity));
_context.TodoItems.Add(entity);
context.TodoItems.Add(entity);
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
return entity.Id;
}

View File

@@ -9,27 +9,22 @@ namespace Hutopy.Application.TodoItems.Commands.DeleteTodoItem;
[Authorize(Policy = Policies.CanDelete)]
public record DeleteTodoItemCommand(int Id) : IRequest;
public class DeleteTodoItemCommandHandler : IRequestHandler<DeleteTodoItemCommand>
public class DeleteTodoItemCommandHandler(
IApplicationDbContext context)
: IRequestHandler<DeleteTodoItemCommand>
{
private readonly IApplicationDbContext _context;
public DeleteTodoItemCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task Handle(DeleteTodoItemCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoItems
var entity = await context.TodoItems
.FindAsync(new object[] { request.Id }, cancellationToken);
Guard.Against.NotFound(request.Id, entity);
_context.TodoItems.Remove(entity);
context.TodoItems.Remove(entity);
entity.AddDomainEvent(new TodoItemDeletedEvent(entity));
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
}
}

View File

@@ -11,18 +11,13 @@ public record UpdateTodoItemCommand : IRequest
public bool Done { get; init; }
}
public class UpdateTodoItemCommandHandler : IRequestHandler<UpdateTodoItemCommand>
public class UpdateTodoItemCommandHandler(
IApplicationDbContext context)
: IRequestHandler<UpdateTodoItemCommand>
{
private readonly IApplicationDbContext _context;
public UpdateTodoItemCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task Handle(UpdateTodoItemCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoItems
var entity = await context.TodoItems
.FindAsync(new object[] { request.Id }, cancellationToken);
Guard.Against.NotFound(request.Id, entity);
@@ -30,6 +25,6 @@ public class UpdateTodoItemCommandHandler : IRequestHandler<UpdateTodoItemComman
entity.Title = request.Title;
entity.Done = request.Done;
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
}
}

View File

@@ -14,18 +14,13 @@ public record UpdateTodoItemDetailCommand : IRequest
public string? Note { get; init; }
}
public class UpdateTodoItemDetailCommandHandler : IRequestHandler<UpdateTodoItemDetailCommand>
public class UpdateTodoItemDetailCommandHandler(
IApplicationDbContext context)
: IRequestHandler<UpdateTodoItemDetailCommand>
{
private readonly IApplicationDbContext _context;
public UpdateTodoItemDetailCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task Handle(UpdateTodoItemDetailCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoItems
var entity = await context.TodoItems
.FindAsync(new object[] { request.Id }, cancellationToken);
Guard.Against.NotFound(request.Id, entity);
@@ -34,6 +29,6 @@ public class UpdateTodoItemDetailCommandHandler : IRequestHandler<UpdateTodoItem
entity.Priority = request.Priority;
entity.Note = request.Note;
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
}
}

View File

@@ -3,18 +3,13 @@ using Microsoft.Extensions.Logging;
namespace Hutopy.Application.TodoItems.EventHandlers;
public class TodoItemCompletedEventHandler : INotificationHandler<TodoItemCompletedEvent>
public class TodoItemCompletedEventHandler(
ILogger<TodoItemCompletedEventHandler> logger)
: INotificationHandler<TodoItemCompletedEvent>
{
private readonly ILogger<TodoItemCompletedEventHandler> _logger;
public TodoItemCompletedEventHandler(ILogger<TodoItemCompletedEventHandler> logger)
{
_logger = logger;
}
public Task Handle(TodoItemCompletedEvent notification, CancellationToken cancellationToken)
{
_logger.LogInformation("Hutopy Domain Event: {DomainEvent}", notification.GetType().Name);
logger.LogInformation("Hutopy Domain Event: {DomainEvent}", notification.GetType().Name);
return Task.CompletedTask;
}

View File

@@ -3,18 +3,13 @@ using Microsoft.Extensions.Logging;
namespace Hutopy.Application.TodoItems.EventHandlers;
public class TodoItemCreatedEventHandler : INotificationHandler<TodoItemCreatedEvent>
public class TodoItemCreatedEventHandler(
ILogger<TodoItemCreatedEventHandler> logger)
: INotificationHandler<TodoItemCreatedEvent>
{
private readonly ILogger<TodoItemCreatedEventHandler> _logger;
public TodoItemCreatedEventHandler(ILogger<TodoItemCreatedEventHandler> logger)
{
_logger = logger;
}
public Task Handle(TodoItemCreatedEvent notification, CancellationToken cancellationToken)
{
_logger.LogInformation("Hutopy Domain Event: {DomainEvent}", notification.GetType().Name);
logger.LogInformation("Hutopy Domain Event: {DomainEvent}", notification.GetType().Name);
return Task.CompletedTask;
}

View File

@@ -4,31 +4,25 @@ using Hutopy.Application.Common.Models;
namespace Hutopy.Application.TodoItems.Queries.GetTodoItemsWithPagination;
public record GetTodoItemsWithPaginationQuery : IRequest<PaginatedList<TodoItemBriefDto>>
public abstract record GetTodoItemsWithPaginationQuery : IRequest<PaginatedList<TodoItemBriefDto>>
{
public int ListId { get; init; }
public int PageNumber { get; init; } = 1;
public int PageSize { get; init; } = 10;
}
public class GetTodoItemsWithPaginationQueryHandler : IRequestHandler<GetTodoItemsWithPaginationQuery, PaginatedList<TodoItemBriefDto>>
public class GetTodoItemsWithPaginationQueryHandler(
IApplicationDbContext context,
IMapper mapper)
: IRequestHandler<GetTodoItemsWithPaginationQuery, PaginatedList<TodoItemBriefDto>>
{
private readonly IApplicationDbContext _context;
private readonly IMapper _mapper;
public GetTodoItemsWithPaginationQueryHandler(IApplicationDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public async Task<PaginatedList<TodoItemBriefDto>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken)
{
Console.WriteLine(request);
return await _context.TodoItems
return await context.TodoItems
.Where(x => x.ListId == request.ListId)
.OrderBy(x => x.Title)
.ProjectTo<TodoItemBriefDto>(_mapper.ConfigurationProvider)
.ProjectTo<TodoItemBriefDto>(mapper.ConfigurationProvider)
.PaginatedListAsync(request.PageNumber, request.PageSize);
}
}

View File

@@ -8,24 +8,17 @@ public record CreateTodoListCommand : IRequest<int>
public string? Title { get; init; }
}
public class CreateTodoListCommandHandler : IRequestHandler<CreateTodoListCommand, int>
public class CreateTodoListCommandHandler(
IApplicationDbContext context)
: IRequestHandler<CreateTodoListCommand, int>
{
private readonly IApplicationDbContext _context;
public CreateTodoListCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task<int> Handle(CreateTodoListCommand request, CancellationToken cancellationToken)
{
var entity = new TodoList();
var entity = new TodoList { Title = request.Title };
entity.Title = request.Title;
context.TodoLists.Add(entity);
_context.TodoLists.Add(entity);
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
return entity.Id;
}

View File

@@ -4,25 +4,20 @@ namespace Hutopy.Application.TodoLists.Commands.DeleteTodoList;
public record DeleteTodoListCommand(int Id) : IRequest;
public class DeleteTodoListCommandHandler : IRequestHandler<DeleteTodoListCommand>
public class DeleteTodoListCommandHandler(
IApplicationDbContext context)
: IRequestHandler<DeleteTodoListCommand>
{
private readonly IApplicationDbContext _context;
public DeleteTodoListCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task Handle(DeleteTodoListCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoLists
var entity = await context.TodoLists
.Where(l => l.Id == request.Id)
.SingleOrDefaultAsync(cancellationToken);
Guard.Against.NotFound(request.Id, entity);
_context.TodoLists.Remove(entity);
context.TodoLists.Remove(entity);
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
}
}

View File

@@ -8,19 +8,14 @@ namespace Hutopy.Application.TodoLists.Commands.PurgeTodoLists;
[Authorize(Policy = Policies.CanPurge)]
public record PurgeTodoListsCommand : IRequest;
public class PurgeTodoListsCommandHandler : IRequestHandler<PurgeTodoListsCommand>
public class PurgeTodoListsCommandHandler(
IApplicationDbContext context)
: IRequestHandler<PurgeTodoListsCommand>
{
private readonly IApplicationDbContext _context;
public PurgeTodoListsCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task Handle(PurgeTodoListsCommand request, CancellationToken cancellationToken)
{
_context.TodoLists.RemoveRange(_context.TodoLists);
context.TodoLists.RemoveRange(context.TodoLists);
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
}
}

View File

@@ -9,25 +9,20 @@ public record UpdateTodoListCommand : IRequest
public string? Title { get; init; }
}
public class UpdateTodoListCommandHandler : IRequestHandler<UpdateTodoListCommand>
public class UpdateTodoListCommandHandler(
IApplicationDbContext context)
: IRequestHandler<UpdateTodoListCommand>
{
private readonly IApplicationDbContext _context;
public UpdateTodoListCommandHandler(IApplicationDbContext context)
{
_context = context;
}
public async Task Handle(UpdateTodoListCommand request, CancellationToken cancellationToken)
{
var entity = await _context.TodoLists
var entity = await context.TodoLists
.FindAsync(new object[] { request.Id }, cancellationToken);
Guard.Against.NotFound(request.Id, entity);
entity.Title = request.Title;
await _context.SaveChangesAsync(cancellationToken);
await context.SaveChangesAsync(cancellationToken);
}
}

View File

@@ -18,7 +18,7 @@ public class UpdateTodoListCommandValidator : AbstractValidator<UpdateTodoListCo
.WithErrorCode("Unique");
}
public async Task<bool> BeUniqueTitle(UpdateTodoListCommand model, string title, CancellationToken cancellationToken)
private async Task<bool> BeUniqueTitle(UpdateTodoListCommand model, string title, CancellationToken cancellationToken)
{
return await _context.TodoLists
.Where(l => l.Id != model.Id)

View File

@@ -8,17 +8,11 @@ namespace Hutopy.Application.TodoLists.Queries.GetTodos;
[Authorize]
public record GetTodosQuery : IRequest<TodosVm>;
public class GetTodosQueryHandler : IRequestHandler<GetTodosQuery, TodosVm>
public class GetTodosQueryHandler(
IApplicationDbContext context,
IMapper mapper)
: IRequestHandler<GetTodosQuery, TodosVm>
{
private readonly IApplicationDbContext _context;
private readonly IMapper _mapper;
public GetTodosQueryHandler(IApplicationDbContext context, IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public async Task<TodosVm> Handle(GetTodosQuery request, CancellationToken cancellationToken)
{
return new TodosVm
@@ -28,9 +22,9 @@ public class GetTodosQueryHandler : IRequestHandler<GetTodosQuery, TodosVm>
.Select(p => new LookupDto { Id = (int)p, Title = p.ToString() })
.ToList(),
Lists = await _context.TodoLists
Lists = await context.TodoLists
.AsNoTracking()
.ProjectTo<TodoListDto>(_mapper.ConfigurationProvider)
.ProjectTo<TodoListDto>(mapper.ConfigurationProvider)
.OrderBy(t => t.Title)
.ToListAsync(cancellationToken)
};

View File

@@ -4,18 +4,13 @@ namespace Hutopy.Application.TodoLists.Queries.GetTodos;
public class TodoListDto
{
public TodoListDto()
{
Items = Array.Empty<TodoItemDto>();
}
public int Id { get; init; }
public string? Title { get; init; }
public string? Colour { get; init; }
public IReadOnlyCollection<TodoItemDto> Items { get; init; }
public IReadOnlyCollection<TodoItemDto> Items { get; init; } = Array.Empty<TodoItemDto>();
private class Mapping : Profile
{