MVC 3 and DependencyResolver - The Ecstasy and the Agony

by coatta 8/19/2011 2:32:00 PM

I started building my first MVC 3 the other day and came across the DependencyResolver mechanism for incorporating 3rd party inversion of control containers. How I rejoiced! I've been using Castle/Windsor for quite some time and have a nice set of capabilities built on top of its interceptor feature. So, I pull in my utility library, grab a Windsor-specific implementation of IDependencyResolver off the net, and start setting up my constructors for injection. I run my sample app, and it all hangs together. My controllers are being instantiated through Windsor and I'm happily making use of my utilities for tracing, logging, timing, etc.

Now its time to make my little sample a little more realistic. I add some model classes, make my views strongly typed, add some forms which submit data back to the application. Its all pretty straightforward, so I am not expecting any problems when I start it up and navigate to the main page. Sadly, it dies. There is an error message about not being able to create an object because a parameterless constructor cannot be found. Naturally, the error message doesn't tell me which class is causing this problem... After a bit, I find that the problem is my new model objects, but that doesn't really make sense because Windsor shouldn't be looking for a parameterless constructor.

I'm puzzling this out when it hits me: The model objects are not being allocated through Windsor, MVC is instantiating them directly. My rejoicing turns to despair. How could they go to all the trouble of setting up an infrastructure to support inversion of control and then not use it uniformly!? OK, I get that model objects are basically data bags and probably shouldn't be referencing services, but an IoC framework is more than just a way to resolve services. As noted above, I've got a bunch of utilities for tracing, timing, debugging, etc. that are all built on top of the core capabilities of Castle/Windsor. And those utilities are useful for model objects. But I can't use them because someone on the MVC team decided that it didn't make sense to use the dependency resolver for model objects.

Now its off to see what other ways MS can inflict emotional damage on me...

ORM's and Locking

by coatta 1/11/2009 11:13:00 PM

An interesting deadlock situation came up in our application recently. We use NHibernate for our ORM and our database is SQL Server. Within the application we've constructed some utility classes for NHibernate so that there is a standard pattern for finding, accessing, and modifying persisten objects. A key part of this is our UnitOfWork class that wraps up an NHibernate session and transaction. All access to persistent objects occurs in the context of a UnitOfWork. When a UnitOfWork is completed it either commits its changes back to the DB or they are aborted.

Initially, the typical pattern for carrying out some changes to a persistent object (or set of objects) looked like:

    using (new UnitOfWork())
    {
       Person p = PersonFactory.FindById(personId);
       p.Salary += 10;
    }

By default, the UnitOfWork commits at the end, so that the change to the Salary property would end up being saved to the DB by this code. Much to our chagrin, we found ourselves getting quite a few deadlocks when using this code.

The trouble with this code arises because, by default, NHibernate acquires a read lock when getting the data from the DB as part of the FindById() call. If multiple threads execute this code concurrently, they can acquire a read lock on the same object since read locks are allowed to be shared. When the transaction commits, the read locks need to be upgraded to write locks (because we are changing the object). The result is a deadlock because the shared read lock cannot be upgraded.

To try and simplify life for the programmer, we decided to add a parameter to the UnitOfWork which would indicated whether the code was read-only or not. That would eliminate the need to determine on a case b case basis what locks should be used for each object. Calls such as FindById() would observe the value of the read-only flag of the current session and modify their locking behaviour accordingly. So, for a UnitOfWork which was not read-only, it would acquire an update lock -- which is used in SQL server to indicate a lock which may need to be upgraded to a write lock later in the transaction.

Overall this was a vary effective strategy. It was a relatively simple programming model and it virtually eliminated all of the deadlocks that we were seeing with the application. In part 2 of this posting, I'll talk about how we eventually needed to go beyond this simple model due to more complex interactions between concurrent threads.


Calendar

<<  March 2024  >>
MoTuWeThFrSaSu
26272829123
45678910
11121314151617
18192021222324
25262728293031
1234567

View posts in large calendar

Disclaimer

My opinions are my own, but you can borrow them if you like.

© Copyright 2024

Sign in