文章目录
- 项目地址
- 一、Application 层
- 1.1 定义CQRS的接口以及其他服务
- 1. Command
- 2. IQuery查询
- 3. 当前时间服务接口
- 4. 邮件发送服务接口
- 1.2 ReserveBooking Command
- 1. 处理传入的参数
- 2. ReserveBookingCommandHandler
- 3. BookingReservedDomainEvent
- 1.3 GetBooking Query
-
项目地址
dbt
airflow
一、Application 层
1.1 定义CQRS的接口以及其他服务

1. Command
ICommand.cs
using Bookify.Domain.Abstractions;
using MediatR;
namespace Bookify.Application.Abstractions.Messaging;
public interface ICommand : IRequest<Result>
{
}
public interface ICommand<TReponse> : IRequest<Result<TReponse>>
{
}
ICommandHandler.cs
namespace Bookify.Application.Abstractions.Messaging;
public interface ICommandHandler<TCommand> : IRequestHandler<TCommand, Result>where TCommand : ICommand
{
}public interface ICommandHandler<TCommand, TResponse> : IRequestHandler<TCommand, Result<TResponse>>where TCommand : ICommand<TResponse>
{
}
2. IQuery查询
using Bookify.Domain.Abstractions;
using MediatR;
namespace Bookify.Application.Abstractions.Messaging;
public interface IQuery<TResponse> : IRequest<Result<TResponse>>
{
}
using Bookify.Domain.Abstractions;
using MediatR;
namespace Bookify.Application.Abstractions.Messaging;
public interface IQueryHandler<TQuery, TResponse> : IRequestHandler<TQuery, Result<TResponse>>where TQuery : IQuery<TResponse>
{
}
3. 当前时间服务接口
namespace Bookify.Application.Abstractions.Clock;public interface IDateTimeProvider
{DateTime UtcNow { get; }
}
4. 邮件发送服务接口
namespace Bookify.Application.Abstractions.Email;
public interface IEmailService
{Task SendAsync(Domain.Users.Email recipient, string subject, string body);
}
1.2 ReserveBooking Command

1. 处理传入的参数
ReserveBookingCommand.cs
:返回值是Guid,参数时4个
using Bookify.Application.Abstractions.Messaging;
namespace Bookify.Application.Bookings.ReserveBooking;
public record ReserveBookingCommand(Guid ApartmentId,Guid UserId,DateOnly StartDate,DateOnly EndDate) : ICommand<Guid>;
2. ReserveBookingCommandHandler
internal sealed class ReserveBookingCommandHandler : ICommandHandler<ReserveBookingCommand, Guid>
{private readonly IUserRepository _userRepository;private readonly IApartmentRepository _apartmentRepository;private readonly IBookingRepository _bookingRepository;private readonly IUnitOfWork _unitOfWork;private readonly PricingService _pricingService;private readonly IDateTimeProvider _dateTimeProvider;public ReserveBookingCommandHandler(IUserRepository userRepository,IApartmentRepository apartmentRepository,IBookingRepository bookingRepository,IUnitOfWork unitOfWork,PricingService pricingService,IDateTimeProvider dateTimeProvider){_userRepository = userRepository;_apartmentRepository = apartmentRepository;_bookingRepository = bookingRepository;_unitOfWork = unitOfWork;_pricingService = pricingService;_dateTimeProvider = dateTimeProvider;}public async Task<Result<Guid>> Handle(ReserveBookingCommand request, CancellationToken cancellationToken){User? user = await _userRepository.GetByIdAsync(request.UserId, cancellationToken);if (user is null){return Result.Failure<Guid>(UserErrors.NotFound);}Apartment? apartment = await _apartmentRepository.GetByIdAsync(request.ApartmentId, cancellationToken);if (apartment is null){return Result.Failure<Guid>(ApartmentErrors.NotFound);}var duration = DateRange.Create(request.StartDate, request.EndDate);if (await _bookingRepository.IsOverlappingAsync(apartment, duration, cancellationToken)){return Result.Failure<Guid>(BookingErrors.Overlap);}var booking = Booking.Reserve(apartment,user.Id,duration,_dateTimeProvider.UtcNow,_pricingService);_bookingRepository.Add(booking);await _unitOfWork.SaveChangesAsync(cancellationToken);return booking.Id;}
}
3. BookingReservedDomainEvent
- 处理 BookingReservedDomainEvent 事件的逻辑,这里只是一个处理的函数,并没有自动执行,只有当发布了事件之后,才会触发
namespace Bookify.Application.Bookings.ReserveBooking;
internal sealed class BookingReservedDomainEventHandler : INotificationHandler<BookingReservedDomainEvent>
{private readonly IBookingRepository _bookingRepository;private readonly IUserRepository _userRepository;private readonly IEmailService _emailService;public BookingReservedDomainEventHandler(IEmailService emailService, IUserRepository userRepository, IBookingRepository bookingRepository){_emailService = emailService;_userRepository = userRepository;_bookingRepository = bookingRepository;}public async Task Handle(BookingReservedDomainEvent notification, CancellationToken cancellationToken){Booking? booking = await _bookingRepository.GetByIdAsync(notification.BookingId, cancellationToken);if (booking is null){return;}User? user = await _userRepository.GetByIdAsync(booking.UserId, cancellationToken);if (user is null){return;}await _emailService.SendAsync(user.Email,"Booking reserved!","You have 10 minutes to confirm this booking");}
}
1.3 GetBooking Query
1. 创建Dapper的链接接口