[Updated May 9, 2007: Clarified contest rules to downgrade some "requirements" to be "suggestions" instead. I.e., there's now a little more wiggle room in the implementation details.]
A contest guaranteed to challenge you! This contest involves integrating Castle Project facilities into an existing project that's pre-wired for Castle Project Windsor. Have you wanted to try out some aspect oriented programming? This just may be a good place to use it.
Background & Problem
In the article, NHibernate Best Practices with ASP.NET, the open-session-in-view technique is employed to begin a transaction at the beginning of each HTTP request, and then to commit the transaction at the end of the request. There are a few drawbacks associated with this:
- If you don't need a transaction, or if you don't even need to talk to the database, you've wasted a bit of useless transactional overhead.
- Having transactions automatically started in an HTTP module can unintentionally begin transactions for unintended items such as images and CSS files depending on IIS settings. (This can also be coded around in the HTTP module, but it's still less than ideal IMO.)
- Since the transaction encompasses the entire HTTP request from start to finish, it's difficult to center the transaction to only a specific section of code.
On the flip side, using an HTTP module greatly simplifies the process of managing the transaction. A few challenges when not using an HTTP module include:
- How can a transaction be started from a project layer without talking to an NHibernate manager class directly?
- Assume a page communicates with two databases at the same time. How can a transaction be cleanly started for one database communication but not the other?
- How can the transaction be managed to begin at the start of a particular method and committed at the end of the method, again, without talking to an NHibernate manager class directly?
The Castle Project Automatic Transaction Management facility is about the cleanest approach to transaction management that I have found. With this facility, in conjunction with the Castle Project Transaction service, it's simple to mark a class as transactional and a particular method as using a transaction, as demonstrated in the following sample code:
This contest involves brining the benefits of the Automatic Transaction Management facility to the "enterprise" NHibernate sample code included in NHibernate Best Practices with ASP.NET.
Up for grabs with this contest is the following book.
Essential Windows Workflow Foundation
By Dharma Shukla, Bob Schmidt.
The prize winning code will also be integrated into the NHibernate Best Practices article's "enterprise" sample project with plenty of accolades for the author in the explanatory comments.
Instructions to Enter
- Make sure you have NUnit installed; available at http://www.nunit.org/.
- Download the NHibernate Best Practice article's "enterprise" sample code from CodeProject.
- Follow the steps described in the article to get the sample code up and running.
- Open NUnit, go to File/Open, then open <solution directory>/EnterpriseSample.Tests/bin/Debug/EnterpriseSample.Tests.dll. Click run and make sure all the tests pass. (You may need to add an assembly redirect for your version of NUnit; an example assembly redirect is described in the article's comments.)
- Complete the integration requirements as described below. Be sure to follow the style of the code that is already in place: classes, methods and public properties in PascalCase, private members in camelCase, etc. Following the style that's already there is always a good rule of thumb when modifying legacy code.
- When finished with the integration, make sure all the unit tests are still passing and that no test is being ignored, zip up your solution and send to email@example.com. If you want to submit your code, but don't want to be considered for the prize, please let me know. The due date for your submission is Monday morning at 8 AM, May 14, US mountain time.
The first correct solution which, in my completely subjective opinion, integrates Castle Project in the cleanest and most simple (to use) manner, will win the contest.
Now Integrate It!
Below is a listing of requirements and/or suggestions for your solution. "Requirements" need to be included in your solution. "Suggestions" need not be implemented exactly as described if you find a better way, in your opinion, to fulfill the stated goals.
- Required: The EnterpriseSample.Presenters.EditCustomerPresenter.Update method must be wrapped within a transaction. This is the ONLY method which needs to have a transaction applied to it.
- Required: The transaction may not be started and stopped within the ICustomerDao data-access object. E.g., adding NHibernateSessionManager.BeginTransaction & CommitTransaction to the DAO is not permitted.
- Required: The EnterpriseSample.Presenters and EnterpriseSample.Web projects must remain ignorant of NHibernateSessionManager.
- Required: The transaction may not be started in any IHttpModule, such as ProjectBase.Data.NHibernateSessionModule, the HTTP module which commits any open transactions. But it's OK if this HTTP module is still used to commit any transactions. (You'll note, in the sample code, that the code which would usually start the transaction has been commented out.)
- Required: As the EnterpriseSample code is configured to work with multiple databases, your solution must be able to support multiple databases as well. An example would be [Transaction("TheDbsUniqueIdentifier")]. This example is only a suggestion and is not required. What is required is that an easy way exists to have the transaction started for one database/session factory and not for another.
- Required: Unit tests must be included to test your solution.
- Suggestion: Beginning a transaction may be done using an attribute such as [Transaction] or by using aspect oriented programming to intercept the method and begin the transaction. Although not required, the attribute approach would be preferred for the purposes of being explicit. If you use an AOP approach, leverage Castle Project's Aspect#.
- Suggestion: The transaction may ultimately be started and stopped via the existing ProjectBase.Data.NHibernateSessionManager class. If your solution requires working around the NHibernateSessionManager to support multiple databases, then that's alright.
- Suggestion: Castle Project's Automatic Transaction Management facility, or a customized variant, may be leveraged but is not required. You're certainly welcome to write your own handler code from the ground up.
- Suggestion: Your transaction management code for handling the attributes should be placed into the project ProjectBase.Data in a new folder called TransactionMgmt.
As a bonus, and added brownie points for getting the prize, develop your solution to commit the transaction immediately after the method which has the transaction attribute declared on top of it. So the transaction will begin at the top of the method and commit as soon as the method completes. Your welcome to use various approaches to this including, but not limited to, attributes to commit the transaction and/or aspect oriented programming (AOP) to commit the transaction when the method completes. Again, if you use an AOP approach, leverage Castle Project's Aspect#.
This challenge has been incredibly fun for me to work on. It's far from trivial and requires you to use a variety of techniques to integrate successfully. Furthermore, Castle Project is a phenomenal grouping of utilities which needs to get greater attention around the development community. Not only can they be used out of the box, but they can also be extended to other purposes...which is one of the challenges here. Consequently, I hope this challenge will give you something fun to work on while learning a few things in the process.
Where to go for Help
The following resources should help explain the code you'll be working with better along with possible solution paths for you to take:
Good luck and let me know if you have any questions!
05-02-2007 5:08 PM