June 24 2024
public class BookingDbContext(DbContextOptions<BookingDbContext> options) : DbContext(options)
{
public DbSet<Traveler> Travelers { get; set; }
public DbSet<BookingSagaData> BookingSagaData { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<BookingSagaData>().HasKey(s => s.CorrelationId);
}
}
public class Traveler
{
public Guid Id { get; set; }
public string Email { get; set; } = string.Empty;
public DateTime BookedOn { get; set; }
}
public class BookingSaga : MassTransitStateMachine<BookingSagaData>
{
public State HotelBooking { get; set; }
public State FlightBooking { get; set; }
public State CarRenting { get; set; }
public State BookingCompleting { get; set; }
public Event<HotelBooked> HotelBooked { get; set; }
public Event<FlightBooked> FlightBooked { get; set; }
public Event<CarRented> CarRented { get; set; }
public Event<BookingCompleted> BookingCompleted { get; set; }
public BookingSaga()
{
InstanceState(x => x.CurrentState);
Event(() => HotelBooked, e => e.CorrelateById(m => m.Message.TravelerId));
Event(() => FlightBooked, e => e.CorrelateById(m => m.Message.TravelerId));
Event(() => CarRented, e => e.CorrelateById(m => m.Message.TravelerId));
Initially
(
When(HotelBooked)
.Then(context =>
{
context.Saga.TravelerId = context.Message.TravelerId;
context.Saga.HotelName = context.Message.HotelName;
context.Saga.FlightCode = context.Message.FlightCode;
context.Saga.CarPlateNumber = context.Message.CarPlateNumber;
})
.TransitionTo(FlightBooking)
.Publish(context => new BookFlight(context.Message.TravelerId, context.Message.Email, context.Message.FlightCode, context.Message.CarPlateNumber))
);
During(FlightBooking,
When(FlightBooked)
.Then(context => context.Saga.FlightBooked = true)
.TransitionTo(CarRenting)
.Publish(context => new RentCar(context.Message.TravelerId, context.Message.Email, context.Message.CarPlateNumber))
);
During(CarRenting,
When(CarRented)
.Then(context =>
{
context.Saga.CarRented = true;
context.Saga.BookingFinished = true;
})
.TransitionTo(BookingCompleting)
.Publish(context => new BookingCompleted
{
TravelerId = context.Message.TravelerId,
Email = context.Message.Email
})
.Finalize());
}
}
public record BookHotel(string Email, string HotelName, string FlightCode, string CarPlateNumber);
public record BookFlight(Guid TravelerId, string Email, string FlightCode, string CarPlateNumber);
public record RentCar(Guid TravelerId, string Email, string CarPlateNumber);
public class HotelBooked
{
public Guid TravelerId { get; set; }
public string Email { get; set; } = string.Empty;
public string HotelName { get; set; } = string.Empty;
public string FlightCode { get; set; } = string.Empty;
public string CarPlateNumber { get; set; } = string.Empty;
}
public class FlightBooked
{
public Guid TravelerId { get; set; }
public string Email { get; set; } = string.Empty;
public string FlightCode { get; set; } = string.Empty;
public string CarPlateNumber { get; set; } = string.Empty;
}
public class CarRented
{
public Guid TravelerId { get; set; }
public string Email { get; set; } = string.Empty;
public string CarPlateNumber { get; set; } = string.Empty;
}
public class BookingCompleted
{
public Guid TravelerId { get; set; }
public string Email { get; set; } = string.Empty;
}
public class BookHotelHandler(BookingDbContext _dbContext) : IConsumer<BookHotel>
{
public async Task Consume(ConsumeContext<BookHotel> context)
{
Console.WriteLine($"Booking hotel {context.Message.HotelName} for traveler {context.Message.Email}");
var traveler = new Traveler
{
Id = Guid.NewGuid(),
Email = context.Message.Email,
BookedOn = DateTime.Now
};
_dbContext.Travelers.Add(traveler);
await _dbContext.SaveChangesAsync();
await context.Publish(new HotelBooked
{
TravelerId = traveler.Id,
HotelName = context.Message.HotelName,
FlightCode = context.Message.FlightCode,
CarPlateNumber = context.Message.CarPlateNumber
});
}
}
public class BookHotelHandler(BookingDbContext _dbContext) : IConsumer<BookHotel>
{
public async Task Consume(ConsumeContext<BookHotel> context)
{
Console.WriteLine($"Booking hotel {context.Message.HotelName} for traveler {context.Message.Email}");
var traveler = new Traveler
{
Id = Guid.NewGuid(),
Email = context.Message.Email,
BookedOn = DateTime.Now
};
_dbContext.Travelers.Add(traveler);
await _dbContext.SaveChangesAsync();
await context.Publish(new HotelBooked
{
TravelerId = traveler.Id,
HotelName = context.Message.HotelName,
FlightCode = context.Message.FlightCode,
CarPlateNumber = context.Message.CarPlateNumber
});
}
}
[HttpPost("bookTrip")]
public IActionResult BookTrip(BookingDetails bookingDetails)
{
_bus.Publish(new BookHotel(bookingDetails.Email, bookingDetails.HotelName, bookingDetails.FlightCode, bookingDetails.CarPlateNumber));
return Accepted();
}
Join 13,250+ subscribers to improve your .NET Knowledge.
Go-to resource for understanding the core concepts of design patterns without the overwhelming complexity. In this concise and affordable ebook, I've distilled the essence of design patterns into an easy-to-digest format. It is a Beginner level. Check out it here.
Every Monday morning, I share 1 actionable tip on C#, .NET & Arcitecture topic, that you can use right away.
Subscribe to the TheCodeMan.net and be among the 13,250+ subscribers gaining practical tips and resources to enhance your .NET expertise.