Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating UI after sending command

I'm struggling in solving this architectural problem, Our system is using NService Bus, and Implementing DDD with EventSourcing using NEventStore and NES. The client application is WPF

I still can't decide what is the best practice to update the UI, for example: I have a UI to create (Batch {Id, StartDate, EndDate ,etc..}), after the user clicks save, I'm sending a command (CreateBatch),

Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc });

Now,

Option #1


Shall I register for a reply as follows:

private void btnSave_Click(object sender,EventsArg e){
    Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc })
       .Register<int>(c=> { 
                     MessageBox.Show("Command Succeded");
                     Close();});
}

and at server side:

public void Hanlde(CreateBatch cmd){
   //initiate aggregate and save it.
   Bus.Return( /*What ?? Success Code?*/);
}

In this case, how to handle errors? (Validation errors, for example there is already a batch starts in the same date ?), since you can only return int or string !!

Option#2:


Send the command, close the window, fake that the record is added in the main grid, until user refresh the grid and get the real one from ReadModel database, or discover that the record is not added yet with no clue about what happened !!

private void btnSave_Click(object sender,EventsArg e){
    Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc });
    Close();
}

Option#3


Send the command, close the window, fake that the record is added in the main grid but mark it as (In progress), wait for (BatchCreated) event to arrive, check that it is the same batch id we sent before, and then mark the record as persisted in the grid.

private void btnSave_Click(object sender,EventsArg e){
    Bus.Send<CreateBatch> (batch => {batch.Id = Guid.NewGuid(); .... etc });
    Close();
}


public class BatchHandler : IHandleMessages<BatchCreated>
{
    public void Handle(BatchCreated evnt)
    {
     if(SomeCachForSentIDS.Contains(evnt.BatchId)
         ///Code to refresh the row in the grid and reflect that the command succeeded.
    }
}

If you have any better options, or have suggestions about the mentioned options, or even some links about how to handle such situation, I would be grateful.

Thank you.

like image 399
Nour Avatar asked May 27 '14 10:05

Nour


2 Answers

One important principle when introducing messaging into a solution like this is to make sure that the command will hardly ever fail (as @Gope mentioned in the comments).

This means that all sorts of validation checks should be performed client-side before sending the message.

Now, even when doing client-side validation, you can still be exposed to race conditions - 2 users creating a batch at the same time that conflict with each other in some way. The way to handle this is to look to clarify the user intent, possibly changing the nature of the task as well as the UI, to make it so that the new command will succeed even in the case of the parallel processing.

Just as a simple stab at a solution, you could redefine the logic to introduce a new state for a batch - like "conflicting", that will be set if another batch starts at the same time. This way the command succeeds (the batch is created), and then you use something like SignalR to push back a notification of this state to the user so they can go about correcting it.

Finally, you might want to reconsider the use of messaging entirely and just go to a simple 2-tier synchronous solution. There's a time and place for every approach.

like image 183
Udi Dahan Avatar answered Sep 29 '22 13:09

Udi Dahan


How to design these user interfaces for asynchronous messaging (especially after we've been indoctrinated into the CRUD mindset) is the million dollar question in each of these systems.

I agree with Udi's assessment 100%. Additionally, your question seems pretty opaque to the exact business requirements, but the CRUD nature of the CreateBatch command and BatchCreated event's names make me wonder if it's really a useful thing to do with messaging at all.

If you find yourself in a situation where you have to wait for CreateBatch to complete so you can do more things to it, maybe you shouldn't have a CreateBatch at all. Maybe you should just be creating something "locally" (that could mean client-side in JavaScript, or as Udi suggests, in the simplest 2-tier database model possible) and then send a command to do the real work (ProcessBatch perhaps?) once everything is complete.

The goal of messaging, after all, is not to completely divorce the web tier from making requests of the database.

like image 45
David Boike Avatar answered Sep 29 '22 11:09

David Boike