Sep 05

Repositories, web apps and optimistic concurrency

Posted in ASP.NET C#      Comments Off on Repositories, web apps and optimistic concurrency

Yesterday, I was looking at some code and I found something like this on a method that handles the confirm click of a web page which triggers an update on a specific domain object:

var aux = Request.Form[“Id”] == null ?
                                new MyObject() :
//update aux’s properties with the values from the other form fields

Ok, can you see anything wrong? I can. What about now? Anything wrong with it? Here’s a scenario that shows how you can get into problems with this:

  1. User A loads object with ID 1 for updating info;
  2. User B also loads the same object for changing some info;
  3. User A submits the form, saving the data to the db;
  4. User B submits the form and ends up overriding the changes made by user A.

By now, I think I can hear some of you saying: “man, why don’t you use some sort of version property? That will save your day!” And I say: “yes, that is a good idea and MyObject class already has that property”. Now, if you’ re on the group that says “then it should work…”, I’ll have to tell you to look again at the code. Do you see the problem now?

By now, you’ve surelly noticed that the problem lies in the fact that you’re loading the object by ID. If you look at the previous list, you can easily see that in step 4 aux will have an object with info submitted by User A instead of having the initial data that was loaded for both User A and User B. This happens because you’re recovering the object from the repository and you’re doing it only by ID. A possible solution for this bug would be adding a method to your repository so that it loads an object by ID and version:

var aux = Request.Form[“Id”] == null ?
                                new MyObject() :
                                 rep.GetByIdAndVersion(Request.Form[“Id”], Request.Form[“Version”]);

Ok,this should work,but I don’t like it. In past ASP.NET projects, I’ve been building serializable objects and I persist them to the ViewState (or Control State, if ViewState is disabled as it should!) of the page and recover them during postbacks. With this second approach, you’ll end up sending more data to the client but you won’t need to perform a database call to get your object.

And yes, this was a bug in a real web app…