In one my projects, I had to implement something with TransactionScope. Here is the code skeleton for that purpose:
Consider the RunOperation method as the main entry point for the awesome feature.
After a while, modifications in the requirement came as usual. Part of the modification was that we have to decide whether to use transaction or not based on a settings injected externally. This settings can come from database or an entry in App.Config file (in my case, it was from App.Config). It is not a complex requirement. However, thinking about how to implement it- I found it quite interesting. Hence, the sharing. I will go through few possible ways to implement it.
First of all, if you do not like to complicate things, you will probably go with the classical “if-else” approach. As the TransactionScope should be used in a using block (for your safety), your code may look like this:
Bad idea. Very bad idea. Next, if you think rationally (read- object oriented design principals), you will probably want to encapsulate the behavior that varies. That is true. However, as the behavior here is whether to have using block with TransactionScope or not have that block totally, you may think of having an abstraction of the whole process. In that case, your code may look like:
And, your RunOperation method may look like:
This is not a bad idea. Though you can make lot of improvements to the above implementation, but you get the idea. However, to me, it was a bit over engineering. Because, the codes inside transaction scope does not vary at all. What varies is whether to use transaction or not. So, why not just encapsulate the behavior of TransactionScope! And that is what I did. I wrote a custom class called ConfigurableTransactionScope and injected a boolean value within constructor- which decides whether or not it should initiate transaction. Here is the code for ConfigurableTransactionScope:
With this wrapping of TransactionScope, your RunOperation method will look like:
Pretty neat! You can do some other cool things with this approach. One of them may be, instead of passing just a boolean value, you can pass a whole object with different settings to configure transaction in the constructor. This settings may include isolation-level, timeout, etc. values loaded externally.
This approach can be useful when you want dynamically configurable behaviors for “something” that you use in a “using” block.
Comments