public async Task<ActionResult> UpdateScholarshipItemAsync([FromBody] ScholarshipItem scholarshipItemToUpdate) { var scholarshipItem = await _scholarshipContext.ScholarshipItems.SingleOrDefaultAsync(i => i.Id == scholarshipItemToUpdate.Id); if (scholarshipItem == null) { return NotFound(new { Message = $"Item with id {scholarshipItemToUpdate.Id} not found." }); } var oldAmount = scholarshipItem.Amount; var raiseScholarshipItemAmountChangedEvent = oldAmount != scholarshipItemToUpdate.Amount; // Update current scholarshipItem scholarshipItem = scholarshipItemToUpdate; _scholarshipContext.ScholarshipItems.Update(scholarshipItem); if (raiseScholarshipItemAmountChangedEvent) // Save scholarshipItem's data and publish integration event through the Event Bus if Amount has changed { //Create Integration Event to be published through the Event Bus var amountChangedEvent = new ScholarshipItemAmountChangedIntegrationEvent(scholarshipItem.Id, scholarshipItemToUpdate.Amount, oldAmount); // Achieving atomicity between original Scholarship database operation and the IntegrationEventLog thanks to a local transaction await _scholarshipIntegrationEventService.SaveEventAndScholarshipContextChangesAsync(amountChangedEvent); // Publish through the Event Bus and mark the saved event as published await _scholarshipIntegrationEventService.PublishThroughEventBusAsync(amountChangedEvent); } else // Just save the updated scholarshipItem because the ScholarshipItem's Amount hasn't changed. { await _scholarshipContext.SaveChangesAsync(); } return CreatedAtAction(nameof(ItemByIdAsync), new { id = scholarshipItemToUpdate.Id }, null); }
public async Task SaveEventAndScholarshipContextChangesAsync(IntegrationEvent evt) { _logger.LogInformation("----- ScholarshipIntegrationEventService - Saving changes and integrationEvent: {IntegrationEventId}", evt.Id); //Use of an EF Core resiliency strategy when using multiple DbContexts within an explicit BeginTransaction(): //See: https://docs.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency await ResilientTransaction.New(_scholarshipContext).ExecuteAsync(async() => { // Achieving atomicity between original scholarship database operation and the IntegrationEventLog thanks to a local transaction await _scholarshipContext.SaveChangesAsync(); await _eventLogService.SaveEventAsync(evt, _scholarshipContext.Database.CurrentTransaction); }); }
public async Task Handle(ApplicationStatusChangedToPaidIntegrationEvent @event) { using (LogContext.PushProperty("IntegrationEventContext", $"{@event.Id}-{Program.AppName}")) { _logger.LogInformation("----- Handling integration event: {IntegrationEventId} at {AppName} - ({@IntegrationEvent})", @event.Id, Program.AppName, @event); //we're not blocking slots foreach (var applicationSlotItem in @event.ApplicationSlotItems) { var scholarshipItem = _scholarshipContext.ScholarshipItems.Find(applicationSlotItem.ScholarshipItemId); scholarshipItem.RemoveSlots(applicationSlotItem.Slots); } await _scholarshipContext.SaveChangesAsync(); } }