public async Task <IActionResult> DepositMessage() { var greetingAsync = new GreetingAsyncEvent("Deposit Hello from the web"); var greeting = new GreetingEvent("Deposit Hello from the web"); await _commandProcessor.DepositPostAsync(greetingAsync); _context.Greetings.Add(greeting); _context.GreetingsAsync.Add(greetingAsync); await _context.SaveChangesAsync(); _commandProcessor.DepositPost(greeting); await _commandProcessor.DepositPostAsync(greetingAsync); return(View("Index")); }
public override async Task <GreetingMade> HandleAsync(GreetingMade @event, CancellationToken cancellationToken = default(CancellationToken)) { var posts = new List <Guid>(); var tx = await _uow.Database.BeginTransactionAsync(cancellationToken); try { var salutation = new Salutation(@event.Greeting); _uow.Salutations.Add(salutation); posts.Add(await _postBox.DepositPostAsync(new SalutationReceived(DateTimeOffset.Now), cancellationToken: cancellationToken)); await _uow.SaveChangesAsync(cancellationToken); await tx.CommitAsync(cancellationToken); } catch (Exception e) { Console.WriteLine(e); await tx.RollbackAsync(cancellationToken); Console.WriteLine("Salutation analytical record not saved"); throw; } await _postBox.ClearOutboxAsync(posts, cancellationToken : cancellationToken); return(await base.HandleAsync(@event, cancellationToken)); }
public override async Task <GreetingMade> HandleAsync(GreetingMade @event, CancellationToken cancellationToken = default(CancellationToken)) { var posts = new List <Guid>(); var tx = await _uow.BeginOrGetTransactionAsync(cancellationToken); try { var salutation = new Salutation(@event.Greeting); await _uow.Database.InsertAsync <Salutation>(salutation, tx); posts.Add(await _postBox.DepositPostAsync(new SalutationReceived(DateTimeOffset.Now), cancellationToken: cancellationToken)); await tx.CommitAsync(cancellationToken); } catch (Exception e) { _logger.LogError(e, "Could not save salutation"); //if it went wrong rollback entity write and Outbox write await tx.RollbackAsync(cancellationToken); return(await base.HandleAsync(@event, cancellationToken)); } await _postBox.ClearOutboxAsync(posts, cancellationToken : cancellationToken); return(await base.HandleAsync(@event, cancellationToken)); }
public async override Task <AddGreetingCommand> HandleAsync(AddGreetingCommand command, CancellationToken cancellationToken = default(CancellationToken)) { await _unitOfWork.BeginTransactionAsync(cancellationToken); try { //Save the new Greeting var greeting = new Greeting() { GreetingMessage = command.GreetingMessage }; await _dataContext.GreetingsRegister.AddAsync(greeting, cancellationToken); //Create an Event for externals var newGreetingAddedEvent = new GreetingAsyncEvent() { Greeting = command.GreetingMessage }; var eventId = await _commandProcessor.DepositPostAsync(newGreetingAddedEvent, cancellationToken : cancellationToken); await _dataContext.SaveChangesAsync(cancellationToken); if (command.ThrowError) { throw new Exception("something broke error"); } else { //Ensure for Testing to Ensure that Contexts are not shared Thread.Sleep(5000); } await _unitOfWork.CommitAsync(cancellationToken); //In Case there is no outbox Sweeper await _commandProcessor.ClearOutboxAsync(new[] { eventId }, cancellationToken : cancellationToken); Console.WriteLine($"Message {command.GreetingMessage} Saved."); } catch (Exception e) { Console.WriteLine(e); await _unitOfWork.RollbackAsync(cancellationToken); Console.WriteLine($"Message {command.GreetingMessage} not Saved."); } return(await base.HandleAsync(command)); }
public override async Task <AddGreeting> HandleAsync(AddGreeting addGreeting, CancellationToken cancellationToken = default(CancellationToken)) { var posts = new List <Guid>(); //We span a Db outside of EF's control, so start an explicit transactional scope var tx = await _uow.Database.BeginTransactionAsync(cancellationToken); try { var person = await _uow.People .Where(p => p.Name == addGreeting.Name) .SingleAsync(cancellationToken); var greeting = new Greeting(addGreeting.Greeting); person.AddGreeting(greeting); //Now write the message we want to send to the Db in the same transaction. posts.Add(await _postBox.DepositPostAsync(new GreetingMade(greeting.Greet()), cancellationToken: cancellationToken)); //write the changed entity to the Db await _uow.SaveChangesAsync(cancellationToken); //write new person and the associated message to the Db await tx.CommitAsync(cancellationToken); } catch (Exception) { //it went wrong, rollback the entity change and the downstream message await tx.RollbackAsync(cancellationToken); return(await base.HandleAsync(addGreeting, cancellationToken)); } //Send this message via a transport. We need the ids to send just the messages here, not all outstanding ones. //Alternatively, you can let the Sweeper do this, but at the cost of increased latency await _postBox.ClearOutboxAsync(posts, cancellationToken : cancellationToken); return(await base.HandleAsync(addGreeting, cancellationToken)); }
public async Task <IActionResult> SaveAndRollbackMessage() { var transaction = await _context.Database.BeginTransactionAsync(); // try // { var greetingAsync = new GreetingAsyncEvent("Hello from the web - 1"); var greeting = new GreetingEvent("Hello from the web - 1"); _context.Greetings.Add(greeting); _context.GreetingsAsync.Add(greetingAsync); await _context.SaveChangesAsync(); _commandProcessor.Post(greeting); await _commandProcessor.PostAsync(greetingAsync); //throw new Exception("Something went wrong"); // } // catch (Exception e) // { await transaction.RollbackAsync(); // } var greetingAsync2 = new GreetingAsyncEvent("Hello from the web - 2"); var greeting2 = new GreetingEvent("Hello from the web - 2"); _context.Greetings.Add(greeting2); _context.GreetingsAsync.Add(greetingAsync2); _commandProcessor.DepositPost(greeting2); await _context.SaveChangesAsync(); await _commandProcessor.DepositPostAsync(greetingAsync2); return(View("Index")); }
public override async Task<AddGreeting> HandleAsync(AddGreeting addGreeting, CancellationToken cancellationToken = default(CancellationToken)) { var posts = new List<Guid>(); //We use the unit of work to grab connection and transaction, because Outbox needs //to share them 'behind the scenes' var tx = await _uow.BeginOrGetTransactionAsync(cancellationToken); try { var searchbyName = Predicates.Field<Person>(p => p.Name, Operator.Eq, addGreeting.Name); var people = await _uow.Database.GetListAsync<Person>(searchbyName, transaction: tx); var person = people.Single(); var greeting = new Greeting(addGreeting.Greeting, person); //Now write the message we want to send to the Db in the same transaction. posts.Add(await _postBox.DepositPostAsync(new GreetingMade(greeting.Greet()), cancellationToken: cancellationToken)); //write the added child entity to the Db await _uow.Database.InsertAsync<Greeting>(greeting, tx); //commit both new greeting and outgoing message await tx.CommitAsync(cancellationToken); } catch (Exception e) { _logger.LogError(e, "Exception thrown handling Add Greeting request"); //it went wrong, rollback the entity change and the downstream message await tx.RollbackAsync(cancellationToken); return await base.HandleAsync(addGreeting, cancellationToken); } //Send this message via a transport. We need the ids to send just the messages here, not all outstanding ones. //Alternatively, you can let the Sweeper do this, but at the cost of increased latency await _postBox.ClearOutboxAsync(posts, cancellationToken:cancellationToken); return await base.HandleAsync(addGreeting, cancellationToken); }
public async Task <Guid> DepositPostAsync <T>(T request, bool continueOnCapturedContext = false, CancellationToken cancellationToken = default) where T : class, IRequest { return(await _commandProcessor.DepositPostAsync(request, continueOnCapturedContext, cancellationToken)); }
public override async Task <UpdateExistingAccountCommand> HandleAsync(UpdateExistingAccountCommand command, CancellationToken cancellationToken = new CancellationToken()) { Guid eventId; using (var uow = new AccountContext(_options)) { using (var trans = uow.Database.BeginTransaction()) { var accountRepositoryAsync = new AccountRepositoryAsync(new EFUnitOfWork(uow)); AggregateLock aggregateLock = null; try { aggregateLock = await accountRepositoryAsync.LockAsync(command.AccountId.ToString(), command.LockBy, cancellationToken); var account = await accountRepositoryAsync.GetAsync(command.AccountId); account.Name = new Name(account, command.Name.FirstName, command.Name.LastName); account.ContactDetails = new ContactDetails(account, command.ContactDetails.Email, command.ContactDetails.TelephoneNumber); account.CardDetails = new CardDetails(account, command.CardDetails.CardNumber, command.CardDetails.CardSecurityCode); account.Addresses = command.Addresses; await accountRepositoryAsync.UpdateAsync(account, aggregateLock, cancellationToken); eventId = await _commandProcessor.DepositPostAsync(new AccountEvent { Id = Guid.NewGuid(), AccountId = account.AccountId.ToString(), Addresses = account.Addresses.Select( addr => new AddressEvent { AddressType = addr.AddressType.ToString(), FistLineOfAddress = addr.FistLineOfAddress, State = addr.State, ZipCode = addr.ZipCode }).ToList(), Name = new NameEvent { FirstName = account.Name.FirstName, LastName = account.Name.LastName }, CardDetails = new CardDetailsEvent { CardNumber = account.CardDetails.CardNumber, CardSecurityCode = account.CardDetails.CardSecurityCode }, ContactDetails = new ContactDetailsEvent { Email = account.ContactDetails.Email, TelephoneNumber = account.ContactDetails.TelephoneNumber } }, false, cancellationToken); trans.Commit(); } finally { if (aggregateLock != null) { await aggregateLock.ReleaseAsync(cancellationToken); } } } } await _commandProcessor.ClearOutboxAsync(new [] { eventId }); return(await base.HandleAsync(command, cancellationToken)); }