<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2486313360029846926</id><updated>2011-11-30T13:53:01.408+01:00</updated><category term='concurrent'/><category term='logging'/><category term='spring'/><category term='development'/><category term='soa'/><category term='aop'/><category term='ndoc3'/><category term='performance'/><category term='social'/><category term='fun'/><category term='architecture'/><category term='eda'/><category term='ioc'/><title type='text'>DevIL's Diary</title><subtitle type='html'>On this blog I will regularly post my thoughts related to Software Engineering, in general as well as .NET specific</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>20</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-6806832514679223793</id><published>2010-09-25T14:57:00.001+02:00</published><updated>2010-09-25T15:09:42.890+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>False Positives in Database Integration Tests</title><content type='html'>&lt;p&gt;You may sometimes find that all your tests pass, but in production your entities cannot be hydrated from the database. Take this example:&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:DFDE9937-D816-47f4-A306-7B60D5CE5AC0:cdab5cc0-ecd3-45da-b1f4-1d4bcfc813fa" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: java; gutter: false; first-line: 1; tab-size: 2;  toolbar: true; "&gt;@PersistenceContext(unitName=&amp;quot;shipmentOrder&amp;quot;)
EntityManager entityManager;

@Test
@Transactional
public void maps_correctly_to_and_from_database() throws Exception {

	ShipmentOrder state = new ShipmentOrder();
	state.setCustomerName(&amp;quot;CALLERNAME&amp;quot;);
	state.getDeliveryAddress().setCountry(&amp;quot;NIRVANA&amp;quot;);

	entityManager.persist(state);
	entityManager.flush(); // enforce writing to the database

	ShipmentOrder foundState = entityManger.find(ShipmentOrder.class, state.getId());

	assertEquals(&amp;quot;CALLERNAME&amp;quot;, foundState.getCustomerName());
	assertEquals(&amp;quot;NIRVANA&amp;quot;, foundState.getDeliveryAddress().getCountry());
}&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This test will happily pass, but the same call fails in production&lt;/strong&gt;. Why? &lt;/p&gt;

&lt;p&gt;Below are the entity classes - note, that JPA by default does not allow @Embeddable's to inherit (see e.g. the &lt;a href="http://docs.redhat.com/docs/en-US/JBoss_Enterprise_Application_Platform/4.2/html-single/Hibernate_Annotations_Reference_Guide/index.html#sect-Hibernate_Annotations_Reference_Guide-Mapping_with_EJB3JPA_Annotations-Mapping_inheritance" target="_blank"&gt;Hibernate Annotations Reference&lt;/a&gt;, section &amp;quot;3.2.4.4. Inherit properties from superclasses&amp;quot; for more details). Even worse, Hibernate does not complain, but silently ignores inherited fields.&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:DFDE9937-D816-47f4-A306-7B60D5CE5AC0:dd6b8217-f680-4970-9f4a-b2784dcf564e" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: java; gutter: false; first-line: 1; tab-size: 2;  toolbar: true; "&gt;@Entity
class ShipmentOrder {
	String customerName;
	@Embedded
	DeliveryAddress deliveryAddress;

	String getCustomerName() { return customerName; }
	DeliveryAddress getDeliveryAddress() { return deliveryAddress; }
}

@Embeddable
class DeliveryAddress extends Address{
	String deliveryLocation;
	String getDeliveryLocation();
}

class Address {
	String country;
	String getCountry();
}&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;So, why does the test pass then?&lt;/p&gt;

&lt;p&gt;The problem is, that while within a transaction, Hibernate reuses objects from the 1st Level cache. This means the our call to &amp;quot;flush()&amp;quot; causes Hibernate to write changes to the database, but the entity instance is still kept in memory. If we execute the &lt;em&gt;find()&lt;/em&gt; method, Hibernate simply returns the entity instance from the cache and will never try to hydrate the instance from the database.&lt;/p&gt;

&lt;h4&gt;Solution&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;EntityManager.clear()&lt;/em&gt; allows to manually purge the 1st level cache. Changing the test to &lt;/p&gt;

&lt;blockquote&gt;
  &lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:DFDE9937-D816-47f4-A306-7B60D5CE5AC0:885d4ef8-6737-480a-8dd8-a33b4e17e15d" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: java; gutter: false; first-line: 1; tab-size: 2;  toolbar: true;  highlight: 4 ;"&gt;repository.store(state);
entityManager.flush(); // enforce writing to the database

entityManager.clear(); // purge 1st level cache

state = repository.findById(state.getId());
&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;will successfully catch the mapping error.&lt;/p&gt;

&lt;p&gt;Here is a method we use in integration tests to automatically flush+purge all persistence contexts defined in Spring:&lt;/p&gt;

&lt;div style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px" id="scid:DFDE9937-D816-47f4-A306-7B60D5CE5AC0:411d8f99-0c14-4e22-855b-60ef357aa5fc" class="wlWriterEditableSmartContent"&gt;&lt;pre class="brush: java; gutter: false; first-line: 1; tab-size: 2;  toolbar: true; "&gt;protected void flushAndClearPersistenceContexts() {
    Map&amp;lt;String, EntityManagerFactory&amp;gt; entityManagers = this.getApplicationContext().getBeansOfType(EntityManagerFactory.class);
    for(EntityManagerFactory emf:entityManagers.values()) {
        EntityManagerHolder emHolder = (EntityManagerHolder) TransactionSynchronizationManager.getResource(emf);
        if (emHolder != null) {
            final EntityManager entityManager = emHolder.getEntityManager();
            try {
                entityManager.flush();
            } catch (TransactionRequiredException e) {
                // ignore - couldn't find a way to properly check if we are within a transaction
            }
            entityManager.clear();
        }
    }
}
&lt;/pre&gt;&lt;!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin.  http://dunnhq.com --&gt;&lt;/div&gt;

&lt;p&gt;&lt;u&gt;&lt;em&gt;NOTE: never use flush() and clear() in your production code as this seriously kills the performance of hibernate&lt;/em&gt;&lt;/u&gt;&lt;/p&gt;

&lt;p&gt;You can find the sample code reproducing this issue on my &lt;a href="git://github.com/eeichinger/com.blogspot.eeichinger.hibernate_integration_test_false_positives.git" target="_blank"&gt;git repository&lt;/a&gt;.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-6806832514679223793?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/6806832514679223793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=6806832514679223793' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6806832514679223793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6806832514679223793'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2010/09/false-positives-in-database-integration.html' title='False Positives in Database Integration Tests'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-6675965184833729620</id><published>2010-01-25T18:24:00.001+01:00</published><updated>2010-01-25T18:24:57.584+01:00</updated><title type='text'>The Danger Of Mislead Solutions: Constructor Over-Injection</title><content type='html'>&lt;p&gt;Recently Jeffrey Palermo blogged about something he calls &lt;a href="http://jeffreypalermo.com/blog/constructor-over-injection-anti-pattern/" target="_blank"&gt;&amp;quot;constructor over-injection anti-pattern&amp;quot;&lt;/a&gt;. This post caused a couple of reactions, in particular &lt;a href="http://blog.ploeh.dk/2010/01/20/RebuttalConstructorOverinjectionAntipattern.aspx" target="_blank"&gt;Mark Seemann's rebuttal&lt;/a&gt; to be mentioned. Mark Seemann already did a nice job arguing against the tight coupling in Jeffrey's proposed solution of (taken from the follow-up)&lt;/p&gt;  &lt;pre class="csharpcode"&gt;IOrderShipper shipper = &lt;span class="kwrd"&gt;new&lt;/span&gt; OrderShipperFactory().GetDefault();&lt;/pre&gt;

&lt;p&gt;to lazily resolve the IOrderShipper reference. Although I agree with Mark, that those lines are as wrong as possible and introduce an even worse smell than the one Jeffrey tried to cure, I disagree with him, that the problem here is the dependency on a concrete type and that we're dealing with the servicelocator antipattern. The real problem with this solution is that it is only a variant of the singleton pattern. Misko Hevery wrote a nice post, why the &lt;a href="http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/" target="_blank"&gt;singleton pattern is a really bad idea&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;What's The Problem?&lt;/h4&gt;

&lt;p&gt;Let's take a step back and look at Jeffery's original problem. He started with the problem, that it took a long time to instantiate the OrderProcessor because of the constructor-dependency on an IOrderShipper. From the fact, that IOrderShipper is not used by OrderProcessor in 100% of the cases, he draws the conclusion, that IOrderShipper should not be a mandatory argument to the OrderProcessor, thus effectivly turning IOrderShipper into an optional dependency of OrderProcessor.&lt;/p&gt;

&lt;h4&gt;Is IOrderShipper Really Optional?&lt;/h4&gt;

&lt;p&gt;What does making IOrderShipper an optional dependency of OrderProcessor buy us? Of course OrderProcessor get's initialized much faster now. But this comes at a price. By removing the dependency from the constructor (or passing it in via .NET 4.0's Lazy&amp;lt;&amp;gt; as some suggested), we are giving up some important advantages.&lt;/p&gt;

&lt;p&gt;For one, we won't get any notice if there's anything wrong with the IOrderShipper until it is actually needed. There might be an important resource like a database not available, a configuration error or whatever. Only when the first user enters a valid order, this user will experience an error. This violates the &lt;a href="http://martinfowler.com/ieeeSoftware/failFast.pdf" target="_blank"&gt;fail fast &amp;amp; early principle&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If everything is configured correctly, this first user also will experience a surprising delay while the system is processing his order, as he has to wait until the IOrderShipper is available. This breaks &lt;a href="http://stevesmithblog.com/blog/principle-of-least-surprise/" target="_blank"&gt;the principle of least surprise&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;The Real Problem: IOrderShipper&lt;/h4&gt;

&lt;p&gt;After all, it is to expect, that the majority of our users will enter a valid order. The conclusion, that IOrderShipper is an optional dependency, is simply plain wrong when looking at the real world scenario. Thus making IOrderShipper an optional dependency of OrderProcessor due to performance issues when instantiating the object graph is just curing a symptom. It is not about healing the real problem: the terrible performance of instantiating the IOrderShipper.&lt;/p&gt;

&lt;p&gt;The lesson I learned from this exercise: always carefully evaluate, that you're drawing the right conclusions from your analysis. It is sometimes too tempting to take the easy path or be mislead and in doing so introduce even bigger problems in the long run than the one currently at hand.&lt;/p&gt;

&lt;p&gt;As a sidenote, I absolutely agree with Jeffrey, that IoC containers are just tools and your application's design should not rely on your container's features. After all, non-invasiveness is one of the fundamentals of IoC.&lt;/p&gt;

&lt;h4&gt;So Constructor Over-Injection Is Not An Issue?&lt;/h4&gt;

&lt;p&gt;In his second post, Jeffrey introduces even more dependencies into OrderProcessor to proof his point. I have to admit, that services classes sometimes tend to grow and serve as a sort of &amp;quot;feature attractors&amp;quot;. In my next post I will look into this problem and provide some thoughts on why this is a problem and how to solve it.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-6675965184833729620?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/6675965184833729620/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=6675965184833729620' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6675965184833729620'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6675965184833729620'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2010/01/danger-of-mislead-solutions-constructor.html' title='The Danger Of Mislead Solutions: Constructor Over-Injection'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-6230994190744912019</id><published>2010-01-10T18:00:00.000+01:00</published><updated>2010-01-10T20:33:03.686+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><title type='text'>Spring.NET AOP - Behind The Scenes (3)</title><content type='html'>&lt;p&gt;In the last installment of this series I showed you how you can leverage &lt;a href="http://www.springframework.net/" target="_blank"&gt;Spring.NET&lt;/a&gt;'s &lt;em&gt;ProxyFactory&lt;/em&gt; to wrap an object with a proxy and add interceptors to this proxy in order to enrich the behavior of your object's methods without having to changing a single line of code. Nevertheless it is quite cumbersome to wrap each single object explicitely.&lt;/p&gt;  &lt;h4&gt;Describing the "Where To Apply"&lt;/h4&gt;  &lt;p&gt;What we are looking for is a more automated approach, where we just want to describe the objects or - more fine grained - methods that we want to have a particular behavior applied. An interceptor ("Advice" in AOP terms) only describes *what* to do (e.g. retrying an operation), thus we need a way to describe *where* to apply it. In AOP terms, every method that can be wrapped by an interceptor is called a &lt;strong&gt;Joinpoint&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/S0oqi1g5UpI/AAAAAAAACQg/HuJgWS3kpXw/s1600-h/image41.png"&gt;&lt;img style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="image" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/S0oqjh84O2I/AAAAAAAACQk/unMRDG_3tts/image_thumb2.png?imgmax=800" border="0" height="202" width="367" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Of course we can taxatively enumerate the list of joinpoints that we want a particular advice to be applied like this:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;Apply RetryInterceptor At
CalculatorWebService.Add
CalculatorWebService.Divide
...&lt;/pre&gt;

&lt;p&gt;but this clearly is not what we really want as in larger applications this quickly requires us to list each and every joinpoint in this list. What want to say something along the lines of&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Apply RetryInterceptor At
All Service Methods&lt;/pre&gt;

&lt;p&gt;Looks much clearer, but how shall we describe that? You can compare it to selecting records from a database table. What we are dealing with here is a set of possible joinpoints and our "where" clause describes the characteristics of those joinpoints that we want to capture by our select statement. Applying this to our example, we can e.g. write&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Apply RetryInterceptor At
ClassName LIKE &lt;span class="str"&gt;'*Service'&lt;/span&gt; AND MethodName LIKE &lt;span class="str"&gt;'*'&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;In AOP terms, such a SELECT statement, selecting a subset of joinpoints out of all possible joinpoints, is called a &lt;strong&gt;Pointcut&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NxkvYPY_Msg/S0oqkKzr-nI/AAAAAAAACQo/CIcMkPRkt0Y/s1600-h/image4.png"&gt;&lt;img style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="image" alt="image" src="http://lh6.ggpht.com/_NxkvYPY_Msg/S0oqkuwBhtI/AAAAAAAACQs/nle1vh4TupY/image_thumb1.png?imgmax=800" border="0" height="307" width="401" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h4&gt;Applying Advices to Pointcuts: Entering Object Post-Processors&lt;/h4&gt;

&lt;p&gt;Now that we have an idea, how we may select a set of joinpoints based on some criteria, how can we apply this technically? Remember, that in Spring you describe your objects using object definitions, a sort of recipe, that tells Spring how to instantiate and configure a particular object. Here's an example of such construction recipes in XML:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt; name=&lt;span class="str"&gt;"Alice"&lt;/span&gt; type=&lt;span class="str"&gt;"Spring.Objects.TestObject"&lt;/span&gt;&amp;gt;           
&amp;lt;property name=&lt;span class="str"&gt;"age"&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;=&lt;span class="str"&gt;"31"&lt;/span&gt;/&amp;gt;
&amp;lt;/&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;

&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt; name=&lt;span class="str"&gt;"Bob"&lt;/span&gt; type=&lt;span class="str"&gt;"Spring.Objects.TestObject"&lt;/span&gt;&amp;gt;
&amp;lt;property name=&lt;span class="str"&gt;"age"&lt;/span&gt; &lt;span class="kwrd"&gt;value&lt;/span&gt;=&lt;span class="str"&gt;"33"&lt;/span&gt;/&amp;gt;
&amp;lt;property name=&lt;span class="str"&gt;"spouse"&lt;/span&gt; &lt;span class="kwrd"&gt;ref&lt;/span&gt;=&lt;span class="str"&gt;"Alice"&lt;/span&gt; /&amp;gt;
&amp;lt;/&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&lt;/pre&gt;

&lt;p&gt;Using such object definitions we can build up whole object graphs, Since instantiation of these objects happens under control of Spring, we can leverage one of Spring's extension points to manipulate an object once it gets instantiated. This extension point is called &lt;strong&gt;"object post-processing"&lt;/strong&gt;. Everytime an object gets instantiated, Spring hands this object to all configured objects that implement the interface &lt;em&gt;IObjectPostProcessor&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NxkvYPY_Msg/S0oqlegqG0I/AAAAAAAACQw/fS8buHdpwd8/s1600-h/image11.png"&gt;&lt;img style="border-width: 0px; display: inline;" title="image" alt="image" src="http://lh4.ggpht.com/_NxkvYPY_Msg/S0oql22O_vI/AAAAAAAACQ0/qXxkAUhzzTI/image_thumb4.png?imgmax=800" border="0" height="250" width="613" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;This is exactly what we need! We can implement our own &lt;em&gt;IObjectPostProcessor&lt;/em&gt; to wrap the target instances within a proxy as needed. A simple implementation using a predicate for deciding which objects to wrap looks like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomAutoProxyCreator : IObjectPostProcessor
{
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Func&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt; matchesPointcut;
&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; IMethodInterceptor[] advices;

&lt;span class="kwrd"&gt;public&lt;/span&gt; CustomAutoProxyCreator(Func&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;, &lt;span class="kwrd"&gt;string&lt;/span&gt;, &lt;span class="kwrd"&gt;bool&lt;/span&gt;&amp;gt; matchesPointcut,
                              &lt;span class="kwrd"&gt;params&lt;/span&gt; IMethodInterceptor[] advices)
{
  &lt;span class="kwrd"&gt;this&lt;/span&gt;.matchesPointcut = matchesPointcut;
  &lt;span class="kwrd"&gt;this&lt;/span&gt;.advices = advices;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; PostProcessBeforeInitialization(&lt;span class="kwrd"&gt;object&lt;/span&gt; instance, &lt;span class="kwrd"&gt;string&lt;/span&gt; objectName)
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; instance;
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; PostProcessAfterInitialization(&lt;span class="kwrd"&gt;object&lt;/span&gt; instance, &lt;span class="kwrd"&gt;string&lt;/span&gt; objectName)
{
  &lt;span class="kwrd"&gt;if&lt;/span&gt; (matchesPointcut(instance, objectName))
  {
    ProxyFactory proxyFactory = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProxyFactory(instance);
    &lt;span class="kwrd"&gt;foreach&lt;/span&gt;(var advice &lt;span class="kwrd"&gt;in&lt;/span&gt; advices)
    {
      proxyFactory.AddAdvice(advice);
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; proxyFactory.GetProxy();
  }
  &lt;span class="kwrd"&gt;return&lt;/span&gt; instance;
}
}&lt;/pre&gt;

&lt;p&gt;We can now add this CustomAutoProxyCreator to our configuration in order to apply caching and retry behaviors to every object, who's object name ends with "*Service":&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[Configuration]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AutoProxyDemoConfig
{
&lt;span class="kwrd"&gt;public&lt;/span&gt; CalculatorWebService TheCalculatorService()
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService();
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; CustomAutoProxyCreator AutoProxyCreator()
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; CustomAutoProxyCreator(
      (instance, name) =&amp;gt; name.EndsWith(&lt;span class="str"&gt;"Service"&lt;/span&gt;),
      &lt;span class="kwrd"&gt;new&lt;/span&gt; CacheInterceptor(), &lt;span class="kwrd"&gt;new&lt;/span&gt; RetryInterceptor()
  );
}
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h4&gt;Reusing Spring.NET's AutoProxy Facilities - DefaultAdvisorAutoProxyCreator&lt;/h4&gt;

&lt;p&gt;Of course you don't need to implement your own IObjectPostProcessor for automatically creating AOP proxies. Spring.NET already comes with a predefined set of implementations that allow you to choose from &lt;a href="http://www.springframework.net/doc-latest/reference/html/aop.html#aop-autoproxy-choices" target="_blank"&gt;various strategies for automatically creating proxies&lt;/a&gt;, &lt;a href="http://www.springframework.net/doc-latest/reference/html/aop.html#aop-advisorautoproxy" target="_blank"&gt;DefaultAdvisorAutoProxyCreator (DAAPC)&lt;/a&gt; being the most flexible and powerful one.&lt;/p&gt;

&lt;p&gt;What makes DAAPC so powerful? Remember our initial discussion about pointcuts and advices. DAAPC allows you to simply add such combinations of pointcuts and advices to the container configuration and will automatically pick them up to do it's magic. For this reason, Spring.NET introduced a special kind of object, a so called "&lt;strong&gt;Advisor&lt;/strong&gt;". An advisor is nothing else than a combination of a pointcut and an advice to apply at this pointcut:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_NxkvYPY_Msg/S0oqmfxB6ZI/AAAAAAAACQ4/hbDK6snBs9Y/s1600-h/image%5B3%5D.png"&gt;&lt;img style="border: 0px none ; display: block; float: none; margin-left: auto; margin-right: auto;" title="image" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/S0oqm3hjlJI/AAAAAAAACQ8/bfQYRB9M9hg/image_thumb.png?imgmax=800" border="0" height="84" width="244" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To leverage DAAPC, add a DAAPC and a list of advisors as needed to your container configuration. DAAPC then will automatically pickup these advisors and apply them. The following example demonstrates, how to apply our advices using this technique:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[Configuration]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DefaultAdvisorAutoProxyDemoConfig
{
&lt;span class="kwrd"&gt;public&lt;/span&gt; CalculatorWebService TheCalculatorService()
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService();
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultAdvisorAutoProxyCreator AutoProxyCreator()
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DefaultAdvisorAutoProxyCreator();
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultPointcutAdvisor CacheServiceCallResultsAdvisor()
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DefaultPointcutAdvisor(
    &lt;span class="kwrd"&gt;new&lt;/span&gt; SdkRegularExpressionMethodPointcut(&lt;span class="str"&gt;@".*Service\.*"&lt;/span&gt;),
    &lt;span class="kwrd"&gt;new&lt;/span&gt; CacheInterceptor()
  );
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultPointcutAdvisor RetryServiceCallResultsAdvisor()
{
  &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; DefaultPointcutAdvisor(
    &lt;span class="kwrd"&gt;new&lt;/span&gt; SdkRegularExpressionMethodPointcut(&lt;span class="str"&gt;@".*Service\.*"&lt;/span&gt;),
    &lt;span class="kwrd"&gt;new&lt;/span&gt; RetryInterceptor()
  );
}
}&lt;/pre&gt;

&lt;p&gt;The advantage of this technique is, that whenever you want to apply a new advice, you just need to add new advisors to your definition and DAAPC automatically will pick them up and apply them.&lt;/p&gt;

&lt;h4&gt;And now the end is near...&lt;/h4&gt;

&lt;p&gt;What a journey. We started by identifiying cross-cutting concerns, refactoring them into separate classes using the &lt;em&gt;decorator&lt;/em&gt; pattern. By introducing &lt;em&gt;interceptors&lt;/em&gt; we made those behaviors reusable across different target classes. Using &lt;em&gt;ProxyFactory&lt;/em&gt;, we even don't have to write any proxy code anymore. Finally, using &lt;em&gt;pointcuts&lt;/em&gt; and Spring.NET's &lt;em&gt;AutoProxy&lt;/em&gt; facilities, we can easily apply advices on any set of objects as needed. By following common sense and step-by-step refactoring, we almost naturally ended up at this mysterious technique called Aspect-Oriented Programming and proofs that there is nothing magically behind this concept. Also it proofs, that Object-Oriented Programming and Aspect-Oriented Programming are not mutually exclusive, but perfectly work together to tame today's application's complexities. &lt;/p&gt;

&lt;p&gt;Nevertheless we are not done yet. Until now we have only discussed the technical solution, &lt;em&gt;how&lt;/em&gt; to implement AOP. In my next post I will discuss, when to use AOP and point out a couple of issues you have to consider when applying AOP.&lt;/p&gt;

&lt;p&gt;As usual, you can &lt;a href="http://devilsdiary.googlegroups.com/web/Spring.Aop-Behind-The-Scenes-3.zip?gda=ExGfpFUAAACB2KfaDTnkPSpY1frltFMa36yfAXFFauhkpYmTMUmEblTXWvKGYUzcEmfbwIuCISC-9D3UXxGUwj5RW8klnJH2vp3MRGeKwgMTrXPQweC60xrtYix3qocOGWUY90Yyf_g&amp;amp;gsc=ox9i1wsAAACmhD4-OSNlIi1f-yPhEj61" target="_blank"&gt;download the sample code&lt;/a&gt; for this post.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-6230994190744912019?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/6230994190744912019/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=6230994190744912019' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6230994190744912019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6230994190744912019'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2010/01/springnet-aop-behind-scenes-3.html' title='Spring.NET AOP - Behind The Scenes (3)'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_NxkvYPY_Msg/S0oqjh84O2I/AAAAAAAACQk/unMRDG_3tts/s72-c/image_thumb2.png?imgmax=800' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-8614266064913307952</id><published>2010-01-04T06:00:00.000+01:00</published><updated>2010-01-04T12:41:50.684+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><title type='text'>Spring. NET AOP - behind the scenes (2)</title><content type='html'>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;This is the second installment of my series about the internals of &lt;a href="http://www.springframework.net/" target="_blank"&gt;Spring.NET&lt;/a&gt; AOP. In my &lt;a href="http://eeichinger.blogspot.com/2009/12/springnet-aop-behind-scenes-1.html" target="_blank"&gt;first post of this series&lt;/a&gt; I described the first step in separating concerns and how we can use the decorator pattern to make our code much better maintainable. Nevertheless we were still left with two major problems:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Changing an interface to our service requires all decorators to be changed &lt;/li&gt;    &lt;li&gt;Lack of reusing decorator logic for other services &lt;/li&gt; &lt;/ul&gt;  &lt;h4&gt;A more generic approach: Interceptors&lt;/h4&gt;  &lt;p&gt;As mentioned, we can do better. Assume we have other services in our application. We do not want to implement the caching or retry code each time and for every method. Code duplication is the root of all evil. Thus we need to improve our solution.  First, let's refactor our retry code into a separate class, that can be used to wrap any arbitrary method call. We will introduce a special interface for these added behaviors and call them interceptors:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IMethodInterceptor
{
 &lt;span class="kwrd"&gt;object&lt;/span&gt; InvokeMethod(Func&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; invokeNext);
}&lt;/pre&gt;

&lt;p&gt;An interceptor implementation gets passed in a delegate. This delegate can either be the method we are wrapping or even another interceptor.  The method we are wrapping is usually called the &lt;em&gt;target method&lt;/em&gt;.  When the delegate is another interceptor, we refer to this as an &lt;em&gt;interceptor chain&lt;/em&gt;, with each interceptor adding its own behavior before calling the target method. Our Retry-interceptor then looks like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RetryInterceptor : IMethodInterceptor
{
 &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; InvokeMethod(Func&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; invokeNext)
 {
   &lt;span class="kwrd"&gt;int&lt;/span&gt; retries = 0;
   &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
   {
     &lt;span class="kwrd"&gt;try&lt;/span&gt;
     {
       &lt;span class="kwrd"&gt;return&lt;/span&gt; invokeNext();
     }
     &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
     {
       retries++;
       &lt;span class="kwrd"&gt;if&lt;/span&gt; (retries &amp;gt;= 3)
       {
         &lt;span class="kwrd"&gt;throw&lt;/span&gt;; &lt;span class="rem"&gt;// retry threshold exceeded, giving up&lt;/span&gt;
       }
       Thread.Sleep(1000); &lt;span class="rem"&gt;// wait a second&lt;/span&gt;
     }
   }
 }
}&lt;/pre&gt;

&lt;p&gt;Notice, that our RetryInterceptor now is absolutely unaware of the target method or its arguments. It just gets passed in a delegate to invoke, which hands over control to either the next interceptor in the chain or the actual target method.&lt;/p&gt;

&lt;p&gt;Now we can implement our interceptor chain in a rather generic way, we will call it our CalculatorProxy and hand it our actual target instance and a list of interceptors. The actual method invocation is a bit tricky, but doable:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CalculatorProxy : ICalculator
{
 &lt;span class="kwrd"&gt;private&lt;/span&gt; ICalculator target;
 &lt;span class="kwrd"&gt;private&lt;/span&gt; IMethodInterceptor[] interceptors;

 &lt;span class="kwrd"&gt;public&lt;/span&gt; CalculatorProxy(ICalculator target, IMethodInterceptor[] interceptors)
 {
   &lt;span class="kwrd"&gt;this&lt;/span&gt;.target = target;
   &lt;span class="kwrd"&gt;this&lt;/span&gt;.interceptors = interceptors;
 }

 &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
 {
   &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;) InvokeInterceptorAtIndex(0, ()=&amp;gt;target.Add(x, y));
 }

 &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; InvokeInterceptorAtIndex(&lt;span class="kwrd"&gt;int&lt;/span&gt; interceptorIndex, Func&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; targetMethod)
 {
   &lt;span class="kwrd"&gt;if&lt;/span&gt; (interceptorIndex &amp;gt;= interceptors.Length)
   {
     &lt;span class="kwrd"&gt;return&lt;/span&gt; targetMethod();
   }
   &lt;span class="kwrd"&gt;return&lt;/span&gt; interceptors[interceptorIndex].InvokeMethod(
           () =&amp;gt; InvokeInterceptorAtIndex(interceptorIndex + 1, targetMethod)
       );
 }
}&lt;/pre&gt;

&lt;p&gt;This proxy implementation accepts calls coming in over the ICalculator.Add() interface method and passes control to the first interceptor in the chain. Initialize our proxy like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ICalculator calc = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorProxy(
                       &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService(),
                       &lt;span class="kwrd"&gt;new&lt;/span&gt; IMethodInterceptor[] { &lt;span class="kwrd"&gt;new&lt;/span&gt; RetryInterceptor() });
&lt;span class="kwrd"&gt;int&lt;/span&gt; sum = calc.Add(2, 5);&lt;/pre&gt;

&lt;p&gt;Each interceptor will invoke the next interceptor in the list if available or the final target:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/SzfcAAdjJGI/AAAAAAAAB5c/LYwriyzSGe0/s1600-h/calculatorproxy_callgraph3.jpg"&gt;&lt;img style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" title="calculatorproxy_callgraph" alt="calculatorproxy_callgraph" src="http://lh5.ggpht.com/_NxkvYPY_Msg/SzfcCyrKUmI/AAAAAAAAB5g/uB8g2-yMbRQ/calculatorproxy_callgraph_thumb1.jpg?imgmax=800" border="0" height="162" width="597" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We have just implemented a mechanism that allows us to add any arbitrary number of interceptors to our proxy!&lt;/p&gt;

&lt;h4&gt;Generating Proxies - Spring's ProxyFactory&lt;/h4&gt;

&lt;p&gt;Of course we implemented our interception mechanism for one method only yet. Assume we have to extend the capabilities of our remote calculator and add a new Divide() method. How would the proxy implementation of this method look like? Look at this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt; Divide(&lt;span class="kwrd"&gt;double&lt;/span&gt; dividend, &lt;span class="kwrd"&gt;double&lt;/span&gt; divisor)
{
 &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;)InvokeNext(0, () =&amp;gt; target.Divide(dividend, divisor));
}&lt;/pre&gt;

&lt;p&gt;Comparing this implementation to our previous Add() implementation, the pattern becomes obvious. Both methods hand control to the first interceptor and pass in a delegate to the actual method invocation. No matter how many methods we add, this code will always look the same. Let's refactor the common code for invoking the interceptor chain into a base class &lt;em&gt;AbstractProxy&lt;/em&gt;:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AbstractProxy
{
 &lt;span class="kwrd"&gt;private&lt;/span&gt; IMethodInterceptor[] interceptors;

 &lt;span class="kwrd"&gt;public&lt;/span&gt; AbstractProxy(IMethodInterceptor[] interceptors)
 {
   &lt;span class="kwrd"&gt;this&lt;/span&gt;.interceptors = interceptors;
 }

 &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; InvokeInterceptorAtIndex(&lt;span class="kwrd"&gt;int&lt;/span&gt; interceptorIndex, Func&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; targetMethod)
 {
   &lt;span class="kwrd"&gt;if&lt;/span&gt; (interceptorIndex &amp;gt;= interceptors.Length)
   {
     &lt;span class="kwrd"&gt;return&lt;/span&gt; targetMethod();
   }
   &lt;span class="kwrd"&gt;return&lt;/span&gt; interceptors[interceptorIndex].InvokeMethod(
       () =&amp;gt; InvokeInterceptorAtIndex(interceptorIndex + 1, targetMethod)
     );
 }
}&lt;/pre&gt;

&lt;p&gt;Our CalculatorProxy then will be:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CalculatorProxy : AbstractProxy, ICalculator
{
 &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; ICalculator target;

 &lt;span class="kwrd"&gt;public&lt;/span&gt; CalculatorProxy(ICalculator target, IMethodInterceptor[] interceptors)
   : &lt;span class="kwrd"&gt;base&lt;/span&gt;(interceptors)
 {
   &lt;span class="kwrd"&gt;this&lt;/span&gt;.target = target;
 }

 &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
 {
   &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;)InvokeInterceptorAtIndex(0, () =&amp;gt; target.Add(x, y));
 }

 &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;double&lt;/span&gt; Divide(&lt;span class="kwrd"&gt;double&lt;/span&gt; dividend, &lt;span class="kwrd"&gt;double&lt;/span&gt; divisor)
 {
   &lt;span class="kwrd"&gt;return&lt;/span&gt; (&lt;span class="kwrd"&gt;int&lt;/span&gt;)InvokeInterceptorAtIndex(0, () =&amp;gt; target.Divide(dividend, divisor));
 }
}&lt;/pre&gt;

&lt;p&gt;Even if we implemented other interfaces, these lines would be the same. Luckily, &lt;a href="http://www.castleproject.org/dynamicproxy/index.html" target="_blank"&gt;Castle.DynamicProxy&lt;/a&gt;, &lt;a href="http://code.google.com/p/linfu/" target="_blank"&gt;LinFu&lt;/a&gt; and of course &lt;a href="http://www.springframework.net/" target="_blank"&gt;Spring.NET&lt;/a&gt; come with mechanisms that allow this code to be generated at runtime. Below I will show you, how you can use Spring.NET's &lt;em&gt;ProxyFactory&lt;/em&gt; to automatically generate this proxy code.&lt;/p&gt;

&lt;p&gt;First, to make our interceptor compatible to Spring.NET, we need to implement Spring.NET's &lt;em&gt;IMethodInterceptor&lt;/em&gt; interface for our interceptors (instead of our own &lt;em&gt;IMethodInterceptor&lt;/em&gt; interface as described above):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RetryInterceptor : IMethodInterceptor &lt;span class="rem"&gt;// Spring.NET's interceptor interface!&lt;/span&gt;
{
 &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; Invoke(IMethodInvocation invocation)
 {
   &lt;span class="kwrd"&gt;int&lt;/span&gt; retries = 0;
   &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
   {
     &lt;span class="kwrd"&gt;try&lt;/span&gt;
     {
       &lt;span class="kwrd"&gt;return&lt;/span&gt; invocation.Proceed();
     }
     &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
     {
       retries++;
       &lt;span class="kwrd"&gt;if&lt;/span&gt; (retries &amp;gt;= 3)
       {
         &lt;span class="kwrd"&gt;throw&lt;/span&gt;; &lt;span class="rem"&gt;// retry threshold exceeded, giving up&lt;/span&gt;
       }
       Thread.Sleep(1000); &lt;span class="rem"&gt;// wait a second&lt;/span&gt;
     }
   }
 }
}&lt;/pre&gt;

&lt;p&gt;Notice, that instead of getting passed in a method delegate, Spring.NET's &lt;em&gt;IMethodInterceptor.Invoke()&lt;/em&gt; receives an instance of &lt;em&gt;IMethodInvocation&lt;/em&gt; and calls &lt;em&gt;Proceed()&lt;/em&gt; to hand control to the next interceptor or target method in the chain. In contrast to the simple delegate that we used in our manually coded proxy, the &lt;em&gt;IMethodInvocation&lt;/em&gt; interface allows you to access additional information about the current method call:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IMethodInvocation
{
 &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
 &lt;span class="rem"&gt;/// Get the proxy instance for the current method invocation&lt;/span&gt;
 &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;object&lt;/span&gt; Proxy { get; }
 &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
 &lt;span class="rem"&gt;/// Get the target instance for the current method invocation&lt;/span&gt;
 &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;object&lt;/span&gt; Target { get; }
 &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
 &lt;span class="rem"&gt;/// Get the method info for the current method invocation&lt;/span&gt;
 &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
 MethodInfo Method { get; }
 &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
 &lt;span class="rem"&gt;/// Get the arguments for the current method invocation&lt;/span&gt;
 &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;object&lt;/span&gt;[] Arguments { get; }
 &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
 &lt;span class="rem"&gt;/// Hand control to next interceptor or target&lt;/span&gt;
 &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;object&lt;/span&gt; Proceed();
}&lt;/pre&gt;

&lt;p&gt;Now that we have our interceptors ready, we can use Spring.NET's &lt;em&gt;ProxyFactory&lt;/em&gt; to have the proxy class automatically generated for us. Note, that in the example below the method used to add an interceptor is called "AddAdvice". &lt;em&gt;Advice&lt;/em&gt; is the common term to refer to an action to be taken before or after calling the actual target.  For a more detailled description of common AOP terminology, please refer to the &lt;a href="http://springframework.net/doc-latest/reference/html/aop.html" target="_blank"&gt;Spring.NET AOP reference&lt;/a&gt;. Here's the code to let Spring.NET generate such a proxy instance for us:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ProxyFactory proxyFactory = &lt;span class="kwrd"&gt;new&lt;/span&gt; ProxyFactory();
proxyFactory.Target = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService(); &lt;span class="rem"&gt;// set target&lt;/span&gt;
proxyFactory.AddAdvice( &lt;span class="kwrd"&gt;new&lt;/span&gt; RetryInterceptor() ); &lt;span class="rem"&gt;// add interceptor&lt;/span&gt;

ICalculator calc = (ICalculator) proxyFactory.GetProxy(); &lt;span class="rem"&gt;// create proxy instance&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;The call to &lt;em&gt;GetProxy()&lt;/em&gt; will generate a proxy instance, set the target and add the list of interceptors to the proxy. The result is the same structure we showed above and also the call graph of an interceptor chain looks very familiar:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NxkvYPY_Msg/Sz5jpOKz5gI/AAAAAAAAB5k/jfxocrEGyQM/s1600-h/calculatorproxyfactory_callgraph%5B3%5D.jpg"&gt;&lt;img style="border: 0px none ; display: inline;" title="calculatorproxyfactory_callgraph" alt="calculatorproxyfactory_callgraph" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sz5jpg8cNRI/AAAAAAAAB5o/9BTomazzJRs/calculatorproxyfactory_callgraph_thumb%5B1%5D.jpg?imgmax=800" border="0" height="164" width="655" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The difference is, that we didn't have to write a single line of code for our proxy. This means that we now easily can reuse our RetryInterceptor across all kinds of classes in our application!&lt;/p&gt;

&lt;h4&gt;We want more!&lt;/h4&gt;

&lt;p&gt;Wow, what a journey. We started by separating concerns into their own classes by applying the decorator pattern, implemented our own proxy with a flexible method interception mechanism and finally saw, how Spring.NET's ProxyFactory can be used to do all of this for us automatically. &lt;/p&gt;

&lt;p&gt;Is there anything left on our wishlist? Imagine we have a whole bunch of Service classes in our application that we would like to retry their operations. We'd have to execute the lines to create the proxy, set the target and add the interceptors for each service individually. What about a feature that allows you to just point to a list of objects and tell Spring.NET to wrap those objects in a proxy with a given list of interceptors? &lt;/p&gt;

&lt;p&gt;Indeed the AOP framework of Spring.NET comes with a great feature called "AutoProxying" that makes it easy to automatically apply interceptors to a set of objects. Stay tuned to read how this feature works in the next post of this series!&lt;/p&gt;

&lt;p&gt;As usual you can &lt;a href="http://devilsdiary.googlegroups.com/web/Spring.Aop-Behind-The-Scenes-2.zip?gda=qiWy61UAAACB2KfaDTnkPSpY1frltFMaXpkZjyE8IiQJCXaLxBwrAFTXWvKGYUzcEmfbwIuCISDJ3CqdAKeLvePcPSmxWkVMvp3MRGeKwgMTrXPQweC60xrtYix3qocOGWUY90Yyf_g&amp;amp;gsc=GfMv3AsAAADKQpi3bmMP8zvRdbm1wrZU" target="_blank"&gt;download the example code&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-8614266064913307952?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/8614266064913307952/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=8614266064913307952' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/8614266064913307952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/8614266064913307952'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2010/01/spring-net-aop-behind-scenes-2.html' title='Spring. NET AOP - behind the scenes (2)'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_NxkvYPY_Msg/SzfcCyrKUmI/AAAAAAAAB5g/uB8g2-yMbRQ/s72-c/calculatorproxy_callgraph_thumb1.jpg?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-1567130399039579084</id><published>2009-12-31T16:05:00.000+01:00</published><updated>2009-12-31T16:06:05.962+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='social'/><title type='text'>Happy New Year!</title><content type='html'>&lt;p&gt;Instead of a technical post, today I just want to wish a happy new year to everyone! The promised follow-up post of my AOP series will go online on January 4 in the next decade.&lt;/p&gt;  &lt;p&gt;All the Best and I hope to see you again next year!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-1567130399039579084?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/1567130399039579084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=1567130399039579084' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1567130399039579084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1567130399039579084'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/happy-new-year.html' title='Happy New Year!'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-8830942442783282157</id><published>2009-12-28T18:00:00.000+01:00</published><updated>2009-12-27T22:58:10.577+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='aop'/><title type='text'>Spring.NET AOP - behind the scenes (1)</title><content type='html'>&lt;p&gt;On the forums I see one topic coming up quite often: &amp;quot;Can I advise XY?&amp;quot;. In this multipart post series I will describe the motivation for AOP and the way &lt;a href="http://www.springframework.net/" target="_blank"&gt;Spring.NET&lt;/a&gt; AOP (and most others like &lt;a href="http://www.castleproject.org/dynamicproxy/index.html" target="_blank"&gt;Castle.DynamicProxy&lt;/a&gt; and &lt;a href="http://code.google.com/p/linfu/" target="_blank"&gt;LinFu&lt;/a&gt;) technically work in .NET to give you a better understanding and provide you the knowledge to help answering such questions yourself.&lt;/p&gt;  &lt;h4&gt;The example: Retrying operations&lt;/h4&gt;  &lt;p&gt;Instead of the usual logging example I'd like to show you another useful feature: Retrying operations. For the sake of simplicity let's assume we're calling a webservice method for calculating the sum of two integers.&lt;/p&gt;  &lt;pre class="csharpcode"&gt;CalculatorWebService calc = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService(&amp;quot;http:/...&amp;quot;);
&lt;span class="kwrd"&gt;int&lt;/span&gt; sum = calc.Add(2, 5);&lt;/pre&gt;

&lt;p&gt;Since webservices usually involve calling over the network, they are inherently unsafe and might fail for various reasons. In our application, we would like to retry webservice operations 3 times before giving up, with a 1 second delay between retries. &lt;/p&gt;

&lt;p&gt;There are a couple of ways to implement this requirement, the most direct approach probably by deriving our own class from the webservice client class:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RetryingCalculatorWebService : CalculatorWebService
{
  &lt;span class="kwrd"&gt;public&lt;/span&gt; RetryingCalculatorWebService(&lt;span class="kwrd"&gt;string&lt;/span&gt; url):&lt;span class="kwrd"&gt;base&lt;/span&gt;(url) {}   

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
  {
    &lt;span class="kwrd"&gt;int&lt;/span&gt; retries = 0;
    &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
    {
      &lt;span class="kwrd"&gt;try&lt;/span&gt;
      {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.Add(x, y);
      }
      &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
      {
        retries++;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (retries &amp;gt;= 3)
        {
          &lt;span class="kwrd"&gt;throw&lt;/span&gt;; &lt;span class="rem"&gt;// retry threshold exceeded, giving up&lt;/span&gt;// wait a second&lt;/span&gt;
      }
    }
  }
}&lt;/pre&gt;

&lt;p&gt;There are of course a couple of issues with that approach, the 2 most important are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The code for retrying the operation effectively buries our single line of actual business code. This makes it hard identifying what the code actually does: &lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; RetryingCalculatorWebService : CalculatorWebService
{
  &lt;span class="kwrd"&gt;public&lt;/span&gt; RetryingCalculatorWebService(&lt;span class="kwrd"&gt;string&lt;/span&gt; url):&lt;span class="kwrd"&gt;base&lt;/span&gt;(url) {}   

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
  {&lt;span style="color: white"&gt;
    int retries = 0;
    while(true)
    {
      try
      {
        &lt;/span&gt;&lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.Add(x, y);&lt;span style="color: white"&gt;
      }
      catch(Exception ex)
      {
        retries++;
        if (retries &amp;gt;= 3)
        {
          throw; // retry threshold exceeded, giving up
        }
        Thread.Sleep(1000); // wait a second
      }
    }
  &lt;/span&gt;}
}&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;When implementing this requirement across all our webservice clients we not only end up scattering the same lines of code all over our codebase. A change in the requirement might cause us having to change all our webservice client classes causing a huge amount of work. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_NxkvYPY_Msg/SzfVGbbYIEI/AAAAAAAAB5M/YrV2InmMjoY/s1600-h/image3.png"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_NxkvYPY_Msg/SzfVJv5mC0I/AAAAAAAAB5Q/YRKUdykrYlo/image_thumb1.png?imgmax=800" width="389" height="207" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h4&gt;A manually implemented a solution&lt;/h4&gt;

&lt;p&gt;A structured way for non-intrusively adding behavior to exisiting code is described in the GoF book, the pattern is called &lt;a href="http://www.comp.dit.ie/rlawlor/Des_Prin/Design%20patterns/Decorator.pdf" target="_blank"&gt;&amp;quot;Decorator&amp;quot;&lt;/a&gt;, the basic idea being wrapping the actual target method with additional code. Thus you do not need to modify any existing code, instead you &amp;quot;chain&amp;quot; the various required behaviours, each behaviour implemented in its own class. In contrast to the GoF-pattern, nowadays composition is favoured over inheritance, thus instead of using the inheritance approach, let's introduce an interface to easily chain our behaviors:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; ICalculator
{
  &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y);
}&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;ICalculator calc = &lt;span class="kwrd"&gt;...&lt;/span&gt;;
&lt;span class="kwrd"&gt;int&lt;/span&gt; sum = calc.Add(2, 5);&lt;/pre&gt;

&lt;p&gt;Now we can easily implement our business logic and the infrastructure constraint separately and chain them later as needed:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CalculatorWebService : ICalculator
{
&lt;span class="kwrd"&gt;  public&lt;/span&gt; CalculatorWebService(&lt;span class="kwrd"&gt;string&lt;/span&gt; url) { ... }   

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
  {
    &lt;span class="rem"&gt;// perform actual webservice call&lt;/span&gt;
    &lt;span class="kwrd"&gt;return&lt;/span&gt; ...
  }
}&lt;/pre&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CalculatorRetryDecorator : ICalculator
{
  &lt;span class="kwrd"&gt;private&lt;/span&gt; ICalculator next;

  &lt;span class="kwrd"&gt;public&lt;/span&gt; CalculatorRetryDecorator(ICalculator next) { &lt;span class="kwrd"&gt;this&lt;/span&gt;.next = next; }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; Add(&lt;span class="kwrd"&gt;int&lt;/span&gt; x, &lt;span class="kwrd"&gt;int&lt;/span&gt; y)
  {
    &lt;span class="kwrd"&gt;int&lt;/span&gt; retries = 0;
    &lt;span class="kwrd"&gt;while&lt;/span&gt; (&lt;span class="kwrd"&gt;true&lt;/span&gt;)
    {
      &lt;span class="kwrd"&gt;try&lt;/span&gt;
      {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; next.Add(x, y);
      }
      &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
      {
        retries++;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (retries &amp;gt;= 3)
        {
          &lt;span class="kwrd"&gt;throw&lt;/span&gt;; &lt;span class="rem"&gt;// retry threshold exceeded, giving up&lt;/span&gt;
        }
        Thread.Sleep(1000); &lt;span class="rem"&gt;// wait a second&lt;/span&gt;
      }
    }
  }
}&lt;/pre&gt;

&lt;p&gt;Notice how the CalculatorRetryDecorator delegates the actual work to the next calculator in the chain. Now, whenever our requirements force us to retry calculator operations, we just &amp;quot;chain&amp;quot; the implementations together:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ICalculator calc = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorRetryDecorator( &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService( &amp;quot;http://...&amp;quot; ) );
&lt;span class="kwrd"&gt;int&lt;/span&gt; sum = calc.Add(2, 5);&lt;/pre&gt;

&lt;p&gt;Now, when we discover that our performance is to slow, well - implement a caching decorator that caches method results for a certain amount of time using the same approach and add it to the decorator chain:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ICalculator calc = &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorCacheDecorator( &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorRetryDecorator( &lt;span class="kwrd"&gt;new&lt;/span&gt; CalculatorWebService( &amp;quot;http://...&amp;quot; ) ) );
&lt;span class="kwrd"&gt;int&lt;/span&gt; sum = calc.Add(2, 5);&lt;/pre&gt;

&lt;p&gt;When we call the Add() method,&amp;#160; our call graph looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/SzfVMT4mnWI/AAAAAAAAB5U/5yoZUmL1ksc/s1600-h/calculatordecorator_callgraph14.jpg"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="calculatordecorator_callgraph" border="0" alt="calculatordecorator_callgraph" src="http://lh4.ggpht.com/_NxkvYPY_Msg/SzfVPA2ANxI/AAAAAAAAB5Y/tG4ImB2tpcs/calculatordecorator_callgraph_thumb8.jpg?imgmax=800" width="630" height="182" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;This is only the beginning&lt;/h4&gt;

&lt;p&gt;We already achieved a lot by separating concerns into different classes. Still our solution has some significant weaknesses:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;When we add new methods to our ICalculator, we need to extend all of our decorators &lt;/li&gt;

  &lt;li&gt;We want to reuse the retry logic for other services &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my next post I will address those issues and show you how we can implement a more generic solution.&lt;/p&gt;

&lt;p&gt;Here you can &lt;a href="http://devilsdiary.googlegroups.com/web/Spring.Aop-Behind-The-Scenes-1.zip?gda=tIzI6lUAAACB2KfaDTnkPSpY1frltFMadCt3VPfEOfdhH27zaIQ441TXWvKGYUzcEmfbwIuCISAoMVDnRoU0Fv_mFrYP3_Uxvp3MRGeKwgMTrXPQweC60xrtYix3qocOGWUY90Yyf_g&amp;amp;gsc=6eDNagsAAAAUgRyChrCdPbbxDfY3oxmw" target="_blank"&gt;download the example code&lt;/a&gt; for this post.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-8830942442783282157?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/8830942442783282157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=8830942442783282157' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/8830942442783282157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/8830942442783282157'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/springnet-aop-behind-scenes-1.html' title='Spring.NET AOP - behind the scenes (1)'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_NxkvYPY_Msg/SzfVJv5mC0I/AAAAAAAAB5Q/YRKUdykrYlo/s72-c/image_thumb1.png?imgmax=800' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-6786916544774670977</id><published>2009-12-24T18:17:00.001+01:00</published><updated>2009-12-24T19:47:50.175+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='ioc'/><title type='text'>A little Christmas present - for .NET</title><content type='html'>&lt;p&gt;Just read &lt;a href="http://jandiandme.blogspot.com/2009/12/ein-kleines-weihnachtsgeschenk.html" target="_blank"&gt;Eberhard Wolff's newest blog post&lt;/a&gt; and simply couldn't resist to borrow the idea and show you, how the same things can be done using Spring.NET. First, here's the .NET version of Eberhard's example:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyRepository
{ }

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyService
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; MyRepository MyRepository { get; set; }
}&lt;/pre&gt;

&lt;p&gt;Here it is, the smallest possible Spring.NET object. Notice, due to Java's lack of properties the .NET version is even smaller. Still, no attributes, no Spring dependencies - pure code.&lt;/p&gt;

&lt;p&gt;How do you wire them? Spring.NET's XML configuration unfortunately lacks Spring.Java's component-scanning as demonstrated in Eberhard's post. But using the new &lt;a href="http://eeichinger.blogspot.com/2009/12/merry-xmlless-codeconfig-for-springnet.html" target="_blank"&gt;code-based configuration I presented recently&lt;/a&gt;, you easily can wire your objects by writing&lt;/p&gt;

&lt;pre class="csharpcode"&gt;appContext.Configure(cfg =&amp;gt; cfg
     .Scan(scan =&amp;gt; scan
        .TheCallingAssembly()
        .Include(t =&amp;gt; t.FullName.EndsWith(&lt;span class="str"&gt;&amp;quot;Service&amp;quot;&lt;/span&gt;) || t.FullName.EndsWith(&lt;span class="str"&gt;&amp;quot;Repository&amp;quot;&lt;/span&gt;))
        .With&amp;lt;AutowiringConvention&amp;gt;()
));&lt;/pre&gt;

&lt;p&gt;The example code can be downloaded at &lt;a href="http://devilsdiary.googlegroups.com/web/SmallestSpringObject.zip?gda=d_uas0sAAACB2KfaDTnkPSpY1frltFMaYfgNbjSqQ43J7wNvJk4U0OSxdxP0ehzSOpDome1GplrGfzxqeCjCeGiBQzupLpSYBkXa90K8pT5MNmkW1w_4BQ&amp;amp;gsc=9UTZQRYAAAAavkKsAgdB838sJfHDHudr_V9-HhK9T-WOgGR8fR6z3A" target="_blank"&gt;SmallestSpringObject.zip&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merry Christmas!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-6786916544774670977?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/6786916544774670977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=6786916544774670977' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6786916544774670977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6786916544774670977'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/little-christmas-present-for-net.html' title='A little Christmas present - for .NET'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-1125665461362067685</id><published>2009-12-21T02:48:00.001+01:00</published><updated>2009-12-21T02:48:43.262+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='ioc'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>NetMX &amp; Spring.NET - configure your Apps at runtime</title><content type='html'>&lt;p&gt;Ever wished you could change some settings of your application during runtime? Easily retrieve runtime information from your components? You tried WMI and Performance Counters?&lt;/p&gt;  &lt;p&gt;Well I did and to put it polite: I don't like WMI. Performance Counters are a nice way to retrieve peformance information about an application, but when it comes to changing an application's settings or behavior at runtime, you need another way. WMI is still COM-based, although a &lt;a href="http://msdn.microsoft.com/en-us/library/bb404655.aspx" target="_blank"&gt;WMI.NET&lt;/a&gt; binding is available via the System.Management components. Alas this binding is not complete and functions are spread across different namespaces for historical reasons. To put a long story short: It is nothing for the fainthearted.&lt;/p&gt;  &lt;h4&gt;Brief Introduction to Java Management Extensions (JMX)&lt;/h4&gt;  &lt;p&gt;In the Java universe for this purpose there is &lt;a href="http://java.sun.com/developer/technicalArticles/J2SE/jmx.html" target="_blank"&gt;JMX&lt;/a&gt;. Basically it allows an application to expose management objects via a JMX server. A monitoring client can then connect to this server and dynamically obtain runtime information about the exposed management objects. In contrast to WMI there is no schema involved, everything is discovered dynamically. For instance the server application could expose the following management bean:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; SampleMBean
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; String getHello();
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; setHello(String helloMessage);
    &lt;span class="kwrd"&gt;public&lt;/span&gt; String sayHello();
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Sample implements SampleMBean {

    &lt;span class="kwrd"&gt;private&lt;/span&gt; String hello = &lt;span class="str"&gt;&amp;quot;Hello World(s)!&amp;quot;&lt;/span&gt;;

    &lt;span class="kwrd"&gt;public&lt;/span&gt; Sample() {
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; String getHello() {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; hello;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; setHello(String helloMessage) {
      hello = helloMessage;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; String sayHello() {
      &lt;span class="kwrd"&gt;return&lt;/span&gt; hello;
    }
}&lt;/pre&gt;

&lt;p&gt;Using the &lt;a href="http://java.sun.com/j2se/1.5.0/docs/guide/management/jconsole.html" target="_blank"&gt;JConsole&lt;/a&gt; tool, one can easily connect to this application's virtual machine and remotely retrieve/change the properties as well as invoke the exposed method(s):&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/Sy7T24O21SI/AAAAAAAAB30/ddvY8ovdGbM/s1600-h/image%5B12%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T3dXdflI/AAAAAAAAB34/a0kCmXOAs54/image_thumb%5B6%5D.png?imgmax=800" width="571" height="355" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/Sy7T33f6U_I/AAAAAAAAB38/_CiaUcrNw7Q/s1600-h/image%5B13%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh4.ggpht.com/_NxkvYPY_Msg/Sy7T4gFjHeI/AAAAAAAAB4A/XHd3-dsSyJ0/image_thumb%5B7%5D.png?imgmax=800" width="577" height="278" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The server application may expose its management objects over a variety of different connectors, as it is shown in this image (copied from the &lt;a href="http://en.wikipedia.org/wiki/Java_Management_Extensions" target="_blank"&gt;Wikipedia article about JMX&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;&lt;img style="display: block; float: none; margin-left: auto; margin-right: auto" src="http://upload.wikimedia.org/wikipedia/en/d/db/Jmxarchitecture.png" width="345" height="273" /&gt; &lt;/p&gt;

&lt;h4&gt;And Now: .NET Management Extensions&lt;/h4&gt;

&lt;p&gt;Thanks to the amazing work of &lt;a href="http://szymonpobiega.blogspot.com/" target="_blank"&gt;Szymon Pobiega&lt;/a&gt;, the power of JMX is available for the .NET platform as well. The &lt;a href="http://www.codeplex.com/NetMX" target="_blank"&gt;NetMX implementation is available from CodePlex&lt;/a&gt;. The really nice part is, that it also comes with a working implementation of the &lt;a href="https://ws-jmx-connector.dev.java.net/" target="_blank"&gt;JSR262 JMX connector&lt;/a&gt;, so that it is possible to connect to your .NET application using JConsole (yes, that's true and I'm going to proof that ;-)). Of course NetMX also comes with a .NET version of the console, please check out the project for more. I grabbed the sources and compiled them. After playing around a while, I decided to implement a simple usage scenario. &lt;/p&gt;

&lt;h4&gt;The Sample Scenario&lt;/h4&gt;

&lt;p&gt;Every now and then I wanted to increase decrease the logging level of my applications (among other things ...). Using NetMX it should be easy. And - well it was! Using Spring.NET, it was easy to weave a logging advice around my components, using NetMX it was easy to expose a management object for this logging advice, so that the log settings can be changed at runtime. The picture below illustrates the scenario setup I aimed for:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/Sy7T46f6HbI/AAAAAAAAB4E/P6_5HkTqaCc/s1600-h/image%5B21%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh3.ggpht.com/_NxkvYPY_Msg/Sy7T5ofuGMI/AAAAAAAAB4I/4Z34OoY1HAY/image_thumb%5B11%5D.png?imgmax=800" width="354" height="426" /&gt;&lt;/a&gt; The Logging Advice intercepts every call to the service object and logs the method calls to the log system. By default, logging is turned off, using JConsole I want to change those settings during runtime.&lt;/p&gt;

&lt;p&gt;My sample application again is the MovieFinder application. To make the effect visible, the client code retrieves the movielist every second and prints the timestamp + the moviename on the console. Also the logging system is configured to write to the console, but disabled by default.&lt;/p&gt;

&lt;h4&gt;The Solution&lt;/h4&gt;

&lt;p&gt;The sources for my experiment can be fetched from &lt;a href="http://svn.xp-dev.com/svn/oakinger-springnet-sandbox/POC/Spring.NetMX/trunk" target="_blank"&gt;my subversion repository&lt;/a&gt;. What you also need is the JSR262 enhanced version of JConsole, which is included in the &lt;a href="https://ws-jmx-connector.dev.java.net/" target="_blank"&gt;samples of the JSR262 Connector download&lt;/a&gt;. Unpack the connector download and checkout $/jsr262-ri-ea4/samples/index.html for more.&lt;/p&gt;

&lt;p&gt;So launching the application results in a screen similar to this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T6Aa2o3I/AAAAAAAAB4M/vYA7pgpqySw/s1600-h/image%5B25%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T6q0MRuI/AAAAAAAAB4Q/U-5SLr7BpZM/image_thumb%5B13%5D.png?imgmax=800" width="590" height="162" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now launch JConsole and connect to our .NET application using the url &amp;quot;service:jmx:ws://127.0.0.1:9998/jmxws&amp;quot;:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/Sy7T7CzM5YI/AAAAAAAAB4U/xuLe6cup-nM/s1600-h/image%5B29%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T7i-wWUI/AAAAAAAAB4Y/DbcjKrYF-nc/image_thumb%5B15%5D.png?imgmax=800" width="363" height="302" /&gt;&lt;/a&gt;Expanding the tree shown in the left pane, you should see this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/Sy7T8ApMZeI/AAAAAAAAB4c/8EDBvV7qc64/s1600-h/image%5B38%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T8psIksI/AAAAAAAAB4g/WwF7O1sRteo/image_thumb%5B20%5D.png?imgmax=800" width="553" height="230" /&gt;&lt;/a&gt;&amp;#160; Now let's change some settings. Double-Click into the &amp;quot;Value&amp;quot; column and enter the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/Sy7T9CohbAI/AAAAAAAAB4k/j4mJthCv-Ok/s1600-h/image%5B42%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_NxkvYPY_Msg/Sy7T9gMR0cI/AAAAAAAAB4o/Ym9GDRbL8xk/image_thumb%5B22%5D.png?imgmax=800" width="516" height="221" /&gt;&lt;/a&gt;é voila! Our console has significantly changed now:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/Sy7T-JWs-nI/AAAAAAAAB4s/igPvKXpHJdY/s1600-h/image%5B46%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T-hok4LI/AAAAAAAAB4w/fEHGAkSHOrM/image_thumb%5B24%5D.png?imgmax=800" width="663" height="121" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;We just reconfigured the logging advice on the fly to also log all method calls to our service and also dumps the arguments passed in!&lt;/p&gt;

&lt;p&gt;Here's the configuration snipped required to make this happen (using &lt;a href="http://eeichinger.blogspot.com/2009/12/merry-xmlless-codeconfig-for-springnet.html" target="_blank"&gt;Spring.NET CodeConfig&lt;/a&gt; from my last post):&lt;/p&gt;

&lt;pre class="csharpcode"&gt;var appContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; GenericApplicationContext(&lt;span class="kwrd"&gt;false&lt;/span&gt;);
appContext.Configure()
   .FromConfiguration&amp;lt;MovieFinderConfiguration&amp;gt;()
    .EnableLogging(log =&amp;gt;
    {
       log.TypeFilter = type =&amp;gt; type.IsDefined(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ServiceAttribute), &lt;span class="kwrd"&gt;true&lt;/span&gt;);
       log.Logger.LogLevel = LogLevel.Off;
    })
   .EnableNetMX(netmx =&amp;gt;
   {
     netmx.AddConnector&amp;lt;Jsr262ConnectorServerProvider&amp;gt;(&lt;span class="kwrd"&gt;new&lt;/span&gt; Uri(&lt;span class="str"&gt;&amp;quot;http://0.0.0.0:9998/jmxws&amp;quot;&lt;/span&gt;));
     netmx.ExportMBean&amp;lt;SimpleLoggingManager&amp;gt;();
   });&lt;/pre&gt;

&lt;p&gt;Enjoy and again thanks to Szymon for his great work!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-1125665461362067685?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/1125665461362067685/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=1125665461362067685' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1125665461362067685'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1125665461362067685'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/netmx-springnet-configure-your-apps-at.html' title='NetMX &amp;amp; Spring.NET - configure your Apps at runtime'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_NxkvYPY_Msg/Sy7T3dXdflI/AAAAAAAAB34/a0kCmXOAs54/s72-c/image_thumb%5B6%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-4949619539569916265</id><published>2009-12-17T12:35:00.001+01:00</published><updated>2009-12-17T17:25:10.798+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><title type='text'>Merry XMLless! CodeConfig for Spring.NET</title><content type='html'>&lt;p&gt;Straight to the point: XML is not meant for humans. Fullstop. The only way for humans to deal with XML is when it is hidden behind proper tooling support. Without a tool hiding XAML &lt;a href="http://www.kinlan.co.uk/2005/06/xaml-menu-example.html" target="_blank"&gt;you wouldn't write XAML code by hand&lt;/a&gt;, would you? Currently being on a greenfield project with my team collegues not familar with &lt;a href="http://www.springframework.net/" target="_blank"&gt;Spring.NET&lt;/a&gt; it quickly turned out that XML configuration can be quite a hurdle, burying the gain of power in the pain of configuration. Using the simple &lt;a href="http://www.springframework.net/doc-latest/reference/html/quickstarts.html" target="_blank"&gt;MovieFinder example from the Spring.NET quickstart&lt;/a&gt; examples, I would like to introduce you to a new way to do familar things.&lt;/p&gt;  &lt;h4&gt;Introducing MovieFinder&lt;/h4&gt;  &lt;p&gt;In the following I will use the following - very simple - example to show you different ways of wiring the components. A MovieLister can be used to obtain a list of movies directed by a particular director. To access persistent storage, it uses the MovieFinder repository component: &lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/SyoXhS7kBHI/AAAAAAAAB3o/g8Z_6HXoch0/s1600-h/sample%5B14%5D.jpg"&gt;&lt;img style="border-right-width: 0px; display: block; float: none; border-top-width: 0px; border-bottom-width: 0px; margin-left: auto; border-left-width: 0px; margin-right: auto" title="sample" border="0" alt="sample" src="http://lh5.ggpht.com/_NxkvYPY_Msg/SyoXhxeDZUI/AAAAAAAAB3s/IpiSDPfQMdQ/sample_thumb%5B8%5D.jpg?imgmax=800" width="453" height="107" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Here's how the client code might look like:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;IMovieLister lister = ...
var movies = lister.MoviesDirectedBy(&lt;span class="str"&gt;&amp;quot;Roberto Benigni&amp;quot;&lt;/span&gt;)&lt;/pre&gt;

&lt;h4&gt;The traditional way of wiring&lt;/h4&gt;

&lt;p&gt;The traditional way of configuring the Spring.NET container looks like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;objects&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;='http://www.springframework.net'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;='movieLister'&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;='MovieFinder.Core.MovieLister, MovieFinder.Core'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;constructor-arg&lt;/span&gt; &lt;span class="attr"&gt;index&lt;/span&gt;&lt;span class="kwrd"&gt;='0'&lt;/span&gt; &lt;span class="attr"&gt;ref&lt;/span&gt;&lt;span class="kwrd"&gt;='movieFinder'&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
  
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;='movieFinder'&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt; &lt;span class="kwrd"&gt;='MovieFinder.Data.SimpleMovieFinder, MovieFinder.Data'&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;    
  
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;objects&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: Traditional Configuration&lt;/h6&gt;

&lt;p&gt;There are a couple of problems with that approach, here are some:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;not pleasant to read &lt;/li&gt;

  &lt;li&gt;much 'noise', xml syntax hiding the actual wiring structure &lt;/li&gt;

  &lt;li&gt;lack of refactoring support &lt;/li&gt;

  &lt;li&gt;unmanageable for large object numbers &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can imagine that in large applications without any tool support this can be become very painful. Already less known is the fact that Spring is able to autowire components. Here's the example to autowire components based on type-matching contructor arguments (see the &lt;a href="http://www.springframework.net/doc-latest/reference/html/objects.html#objects-factory-autowire" target="_blank"&gt;reference documentation&lt;/a&gt; for other values of 'default-autowire'):&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;objects&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;='http://www.springframework.net' default-autowire='constructor'&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;

  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;='movieLister'&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;='MovieFinder.Core.MovieLister, MovieFinder.Core' /&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;  
  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;='movieFinder'&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt; &lt;span class="kwrd"&gt;='MovieFinder.Data.SimpleMovieFinder, MovieFinder.Data'&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;    
  
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;objects&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: Using constructor autwiring&lt;/h6&gt;

&lt;p&gt;This saves you from having to manually specifiying all dependencies. Of course, renaming your classes still may break this configuration.&lt;/p&gt;

&lt;p&gt;Mark Pollack blogged an extensive post about &lt;a href="http://blog.springsource.com/2008/01/04/spring-net-11-and-container-configuration/" target="_blank"&gt;configuring the Spring.NET container&lt;/a&gt;, including the even less known container API for configuring the container.&lt;/p&gt;

&lt;h4&gt;&lt;strong&gt;Going fluent&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;A lot of frameworks out there have already introduced a configuration style known as &lt;a href="http://martinfowler.com/bliki/FluentInterface.html" target="_blank"&gt;fluent API&lt;/a&gt;. A nice example for the &lt;a href="http://using.castleproject.org/display/IoC/Strongly+Typed+property+wiring+with+Fluent+Registration+API" target="_blank"&gt;Windsor container can be found here&lt;/a&gt;. There's a lot more, &lt;a href="http://wiki.fluentnhibernate.org/Getting_started" target="_blank"&gt;Fluent NHibernate&lt;/a&gt; being another very populare example.&lt;/p&gt;

&lt;p&gt;Recently, Tom Farnbauer released such a fluent configuration API for Spring.NET, &lt;a href="http://code.google.com/p/spring-recoil/" target="_blank"&gt;Recoil for Spring.NET&lt;/a&gt;. Using Recoil, our MovieFinder example could look like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyWiringContainer : WiringContainer
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetupContainer()
    {
        Define( () =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieFinder() )
             .As&amp;lt;IMovieFinder&amp;gt;;

        Define( () =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieLister( Wire&amp;lt;IMovieFinder&amp;gt;() ) )
             .As&amp;lt;IMovieLister&amp;gt;;
    }&lt;br /&gt; 
}

var myContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; GenericApplicationContext();
myContext.Configure()
  .With&amp;lt;MyWiringContainer&amp;gt;();
myContext.Refresh();&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: Wiring using Recoil for Spring.NET&lt;/h6&gt;

&lt;p&gt;Unfortunately I quickly found while introducing Recoil into my current project, that the API has some flaws and - after all - when looking at fluent apis, they usually add as much codenoise to your configuration as xml already does. Also fluent APIs tend to be less extensible than other approaches. Imho Fluent NHibernate suffers this fate a lot (probably others too, but this is the latest example crossing my way). &lt;/p&gt;

&lt;p&gt;Of course we already achieved at least 1 important goal: We are safe against refactoring. Any class moves or renames will automatically be reflected in our configuration - because it is code.&lt;/p&gt;

&lt;h4&gt;Back to the whiteboard&lt;/h4&gt;

&lt;p&gt;I didn't find any of those approaches really satisfying. After all, all I want to do is&lt;/p&gt;

&lt;pre class="csharpcode"&gt;var movieFinder = &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieFinder();
var movieLister = &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieLister( movieFinder );&lt;/pre&gt;

&lt;p&gt;So lets start with the least minimal configuration container I can think of. A simple class, who's member methods return the objects you are asking for:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MovieFinderConfiguration 
{
   &lt;span class="kwrd"&gt;public&lt;/span&gt; IMovieFinder MovieFinder() 
  {
     &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieFinder();
  }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; IMovieLister MovieLister()
  {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieLister( MovieFinder() )
  }
}&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: Wiring using ... plain C#&lt;/h6&gt;

&lt;p&gt;This already does a lot of what we want:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;it is readable &lt;/li&gt;

  &lt;li&gt;it doesn't cause more codenoise than your standard code would have &lt;/li&gt;

  &lt;li&gt;we have full refactoring support &lt;/li&gt;

  &lt;li&gt;we automatically get the whole object graph once we call MovieLister(): &lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="csharpcode"&gt;var container = &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieFinderConfiguration();
var movieLister = container.MovieLister();
var movies = movieLister.MoviesDirectedBy(&lt;span class="str"&gt;&amp;quot;Roberto Bergnini&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: Obtaining the object graph from our C# &amp;quot;container&amp;quot;&lt;/h6&gt;

&lt;p&gt;Unfortunately our minimal container is lacking a couple of things:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;no support for managing the object lifecycle - everytime we call MovieLister() it will return a new graph &lt;/li&gt;

  &lt;li&gt;no support for applying aspects to care for crosscutting concerns &lt;/li&gt;

  &lt;li&gt;no support for all the other features you get from the containers out there &lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;New on stage: CodeConfig for Spring.NET&lt;/h4&gt;

&lt;p&gt;Rooting in &lt;a href="http://blog.springsource.com/2006/11/28/a-java-configuration-option-for-spring/" target="_blank"&gt;a great idea of Rod Johnson&lt;/a&gt;, &lt;a href="http://blog.springsource.com/author/cbeams/" target="_blank"&gt;Chris Beams&lt;/a&gt; started working on bringing this idea to the Java world, the result is &lt;a href="http://www.springsource.org/javaconfig" target="_blank"&gt;JavaConfig&lt;/a&gt; (and since yesterday's release of our mother-project integral part of &lt;a href="http://blog.springsource.com/2009/12/16/spring-framework-3-0-goes-ga/" target="_blank"&gt;Spring 3.0&lt;/a&gt;, congrats at this point to the Java team!). &lt;a href="http://blog.springsource.com/author/mpollack/" target="_blank"&gt;Mark Pollack&lt;/a&gt; implemented the first POC for Spring.NET, due to the needs in my current project, I decided to take that POC and continue develop it.&lt;/p&gt;

&lt;p&gt;Yet again, Spring.NET surprised me. Due to being incredibly flexible, it was almost a breeze to merge the above mentioned concept with the container infrastructure. How does our MovieFinder look like using CodeConfig? Simple:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[Configuration]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MovieFinderConfiguration 
{
   &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; IMovieFinder MovieFinder() 
  {
     &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieFinder();
  }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; IMovieLister MovieLister()
  {
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MovieLister( MovieFinder() )
  }
}&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: The CodeConfig configuration - not much difference!&lt;/h6&gt;

&lt;p&gt;Note the additional [Configuration] attribute and the &amp;quot;virtual&amp;quot; keyword added to the methods. Now feed this configuration into the Spring.NET application context and retrieve an instance of the IMovieLister:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;var appContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; GenericApplicationContext();
appContext.Configure()
    .FromConfiguration&amp;lt;MovieFinderConfiguration&amp;gt;();
ApplicationContext.Refresh();

var movieLister = appContext.GetObject&amp;lt;IMovieLister&amp;gt;();
var movies = movieLister.MoviesDirectedBy(&lt;span class="str"&gt;&amp;quot;Roberto Bergnini&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

&lt;h6 align="center"&gt;Code Example: retrieving an IMovieFinder from an CodeConfig-configured application context&lt;/h6&gt;

&lt;p&gt;Neat, isn't it? This means you can write your configuration in the simplest possible way and still can leverage the full power of the IoC container. Enabling logging on your services? No problem:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;appContext.Configure() &lt;br /&gt;    .FromConfiguration&amp;lt;MovieFinderConfiguration&amp;gt;() &lt;br /&gt;    .EnableLogging(cfg =&amp;gt;
    {
        cfg.TypeFilter = type =&amp;gt; type.IsDefined(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(ServiceAttribute), &lt;span class="kwrd"&gt;true&lt;/span&gt;);
        cfg.Logger.LogExecutionTime = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        cfg.Logger.LogMethodArguments = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        cfg.Logger.LogReturnValue = &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        cfg.Logger.LogLevel = LogLevel.Trace;
    });&lt;/pre&gt;

&lt;h4&gt;Using Conventions for Configuration&lt;/h4&gt;

&lt;p&gt;You don't want to configure each object manually in a large application? Use &lt;strong&gt;component-scanning&lt;/strong&gt;, a feature that I shamelessly stole from StructureMap:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;appContext.Configure() 
    .Scan(s =&amp;gt; s                
        .AssemblyOfType&amp;lt;MovieLister&amp;gt;()
        .AssemblyOfType&amp;lt;SimpleMovieFinder&amp;gt;()
        .Include(t =&amp;gt; t.IsDefined(&lt;span class="kwrd"&gt;typeof&lt;/span&gt; (ComponentAttribute), &lt;span class="kwrd"&gt;true&lt;/span&gt;))
        .With&amp;lt;TypeNamingConvention&amp;gt;()
        .With&amp;lt;AutowiringConvention&amp;gt;()
    );&lt;/pre&gt;

&lt;h4&gt;Sources, Documentation and Next Steps&lt;/h4&gt;

&lt;p&gt;At this moment, you can find the sources in &lt;a href="http://svn.xp-dev.com/svn/oakinger-springnet-sandbox/POC/Spring.Config/trunk" target="_blank"&gt;my public SVN repository at XP-Dev&lt;/a&gt;. Note, that the code will move to &lt;a href="https://src.springframework.org/svn/se-config-net/trunk" target="_blank"&gt;SpringSource's CodeConfig for Spring.NET repository&lt;/a&gt; here at a later stage.&lt;/p&gt;

&lt;p&gt;For a quick overview of what is already possible, &lt;a href="http://svn.xp-dev.com/svn/oakinger-springnet-sandbox/POC/Spring.Config/trunk/examples/MovieFinder/MovieFinder.Tests/" target="_blank"&gt;check out the various configuration examples for the MovieFinder&lt;/a&gt; example there. Documentation is missing, but reading the &lt;a href="http://static.springsource.org/spring-javaconfig/docs/1.0.0.M4/reference/pdf/spring-javaconfig-reference.pdf" target="_blank"&gt;JavaConfig reference&lt;/a&gt; will give you a good overview of the features. For the component-scanning feature read Jeremy Miller's introduction on &lt;a href="http://structuremap.sourceforge.net/ScanningAssemblies.htm" target="_blank"&gt;assembly scanning&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Beware that this is still a moving target, consider it not being more than a preview yet. But I'd love you to grab the sources, play around and let me know what you think - keen on hearing your feedback!&lt;/p&gt;

&lt;p&gt;The first milestone of CodeConfig is scheduled for end of January - and don't forget to check, later this day, &lt;a href="http://www.springframework.net/" target="_blank"&gt;Spring.NET 1.3.0 GA will be released&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Merry XMLless!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-4949619539569916265?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/4949619539569916265/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=4949619539569916265' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/4949619539569916265'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/4949619539569916265'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/merry-xmlless-codeconfig-for-springnet.html' title='Merry XMLless! CodeConfig for Spring.NET'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_NxkvYPY_Msg/SyoXhxeDZUI/AAAAAAAAB3s/IpiSDPfQMdQ/s72-c/sample_thumb%5B8%5D.jpg?imgmax=800' height='72' width='72'/><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-1196368159006689604</id><published>2009-12-14T06:00:00.000+01:00</published><updated>2009-12-14T11:14:50.635+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='social'/><title type='text'>Post-Rational</title><content type='html'>&lt;p&gt;Due to my boss requesting an architecture review, I just find myself trying to put together all those pen&amp;amp;paper discussions I had with people on the team and rethinking the decisions I have made on how the project is set up and the application is structured.&lt;/p&gt;  &lt;p&gt;While doing this, I find myself in a rather interesting situation: I realize that quite a lot of my decisions were based on intuition (which is of course likely driven by experience). Those decisions were not the result of a traditional, concious Analysis-Thesis-Synthesis approach. Much more, the process obviously happened somewhere in the back of my mind and at some point it comes back to the surface and presents me a solution that just "feels" right. Luckily most of those solutions proof useful over time and withstand all kinds of project challenges.&lt;/p&gt;  &lt;p&gt;Nevertheless it leaves me thoughtfully. Should I break my habits and switch to e.g. famous +/- lists? How do I explain certain decisions? "I have a good feeling" is hardly an explanation my boss will eat... &lt;/p&gt;  &lt;p&gt;I think Kevlin Hennley mentioned it in his talk "&lt;a href="http://www.infoq.com/presentations/Five-Considerations-for-Software-Architects" target="_blank"&gt;Five Considerations for Software Architects&lt;/a&gt;" that there is nothing wrong about making intuitive decisions. After all intuition comes a lot from experience. But "I had the idea under the shower" is likely an explanation that not all people will accept. People are different, &lt;a href="http://en.wikipedia.org/wiki/Myers-Briggs_Type_Indicator" target="_blank"&gt;Myers-Briggs&lt;/a&gt; spent a lot of time on this - and a lot of people don't take intuition as an argument. It always makes sense to rationalize your decisions afterwards, so that everyone can understand them. If your decisions proof right, it should be easy to rationalize them anyway.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-1196368159006689604?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/1196368159006689604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=1196368159006689604' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1196368159006689604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1196368159006689604'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/post-rational.html' title='Post-Rational'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-5200949625513709600</id><published>2009-12-10T09:22:00.001+01:00</published><updated>2009-12-10T09:22:44.862+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='development'/><title type='text'>Sniff HTTP traffic with ASP.NET Development Webserver</title><content type='html'>&lt;p&gt;During developing webapplications or -services, every now and then you will face a strong desire to be able to see the HTTP traffic that is sent back and forth between a client and the webserver. &lt;/p&gt;  &lt;h4&gt;Tracing local HTTP traffic is not easy&lt;/h4&gt;  &lt;p&gt;You will quickly find out, that this task sounds easier than it actually is when your client and your server reside on the same machine. There are tools like &lt;a href="http://www.fiddler2.com/" target="_blank"&gt;Fiddler&lt;/a&gt; (and tons of others, but this is my favorite), but they all suffer the same problem: Requests to localhost/127.0.0.1 cannot be captured because they are optimized by the windows network stack and bypass the usual hooks used by capturing tools. Thus you either need to use your network card's IP address for submitting requests or - if you don't have a local ipaddress when e.g. you use DHCP and are disconnected from the network - you need to install the MS Loopback Adapter and use this adapter's IP address (see installing &lt;a title="Installing MS Loopback Adapter" href="http://www.webxpert.ro/andrei/2008/01/02/microsoft-loopback-adapter-manual-install-on-2000-xp-2003-vista/" target="_blank"&gt;MS Loopback Adapter&lt;/a&gt;)&lt;/p&gt;  &lt;h4&gt;ASP.NET Development Webserver is locked down on &amp;quot;localhost&amp;quot;&lt;/h4&gt;  &lt;p&gt;If you are like me and like the ASP.NET Development Webserver (aka &amp;quot;Cassini&amp;quot; or &amp;quot;WebDev.Webserver&amp;quot;) that comes with Visual Studio (and recently also with the &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=c17ba869-9671-4330-a63e-1fd44e0e2505" target="_blank"&gt;Windows 7 SDK&lt;/a&gt;), you can't use it to capture traffic. Probably due to legal issues, the ASP.NET Development WebServer (aka Cassini) contains code that binds the TCP socket to the 127.0.0.1 address only and also contains a check, that the requesting client resides on localhost. In this case you have 2 choices: &lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;a) setup a Webapplication in IIS this is possible but nasty when you want to do it in a build script&lt;/p&gt;    &lt;p&gt;b) follow the instructions below to patch the WebDev.WebHost.dll on your system&lt;/p&gt; &lt;/blockquote&gt;  &lt;h4&gt;Steps to patch WebDev.WebServer&lt;/h4&gt;  &lt;p&gt;Note: All steps below assume you have .NET 3.5 Service Pack 1 and the Windows 7 SDK installed. But with basic familarity of IL code you shouldn't have much problems applying those steps to e.g. the version of WebDev.WebServer that comes with VS 2005 (note, that this version resides under the installroot of VS!)&lt;/p&gt;  &lt;h5&gt;Step 1&lt;/h5&gt;  &lt;p&gt;Create a new directory &amp;quot;C:\patchcassini&amp;quot; that we will use to work and change to this directory on the commandline. You can create any directory you want, but I will refer to it as C:\patchcassini below.&lt;/p&gt;  &lt;h5&gt;Step 2&lt;/h5&gt;  &lt;p&gt;Copy the WebDev.WebHost.dll from the GAC to your working directory and disassemble into an IL script. The following batch script shows how this is done:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;set&lt;/span&gt; SDKHOME=C:\Program Files\Microsoft SDKs\Windows\v7.0




cd C:\patchcassini

&lt;span class="rem"&gt;rem refresh copy from GAC&lt;/span&gt;
copy /Y C:\Windows\assembly\GAC_32\WebDev.WebHost\9.0.0.0__b03f5f7f11d50a3a\WebDev.WebHost.dll .

&lt;span class="rem"&gt;REM create backup&lt;/span&gt;
copy WebDev.WebHost.dll WebDev.WebHost.original.dll

&lt;span class="rem"&gt;REM disassemble&lt;/span&gt;
&lt;span class="str"&gt;&amp;quot;%SDKHOME%\bin\ildasm.exe&amp;quot;&lt;/span&gt; WebDev.WebHost.original.dll /out=WebDev.WebHost.il&lt;/pre&gt;

&lt;p&gt;This will create 2 new files in your folder: WebDev.WebHost.il and WebDev.WebHost.res. Note that the script also creates a backup of the original assembly&lt;/p&gt;

&lt;h5&gt;Step 3&lt;/h5&gt;

&lt;p&gt;Patch the generated IL script. There are 2 things you have to do:&lt;/p&gt;

&lt;p&gt;1) Open the script in any editor and find &amp;amp; replace all occurrences of [System]System.Net.IPAddress::Loopback with [System]System.Net.IPAddress::Any&lt;/p&gt;

&lt;p&gt;2) Find the method body of Connection::get_IsLocal() (just search for this string), you will see something like&lt;/p&gt;

&lt;pre class="csharpcode"&gt;.method assembly hidebysig specialname
        instance bool get_IsLocal() cil managed
{
 ....
} &lt;span class="rem"&gt;// end of method Connection::get_IsLocal&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Replace the whole method body with the code as shown below:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;.method assembly hidebysig specialname
        instance &lt;span class="kwrd"&gt;bool&lt;/span&gt;  get_IsLocal() cil managed
{
.maxstack  2
IL_0014:  ldc.i4.1
IL_0015:  ret
} &lt;span class="rem"&gt;// end of method Connection::get_IsLocal&lt;/span&gt;&lt;/pre&gt;

&lt;h5&gt;Step 4&lt;/h5&gt;

&lt;p&gt;You need to recompile the IL script and reinstall the patched dll into the GAC. Since we also modified a signed dll, we need to turn off signature validation for this dll. The batch script below shows how this is done:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;set&lt;/span&gt; FRAMEWORKHOME=C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727
&lt;span class="kwrd"&gt;set&lt;/span&gt; SDKHOME=C:\Program Files\Microsoft SDKs\Windows\v7.0

&lt;span class="rem"&gt;REM recompile the patched IL script into WebDev.WebHost.dll&lt;/span&gt;
%FRAMEWORKHOME%\ilasm.exe /output=WebDev.WebHost.dll /quiet /resource=WebDev.WebHost.res /debug /dll WebDev.WebHost.il

&lt;span class="rem"&gt;rem Remove validation&lt;/span&gt;
&lt;span class="str"&gt;&amp;quot;%SDKHOME%\bin\sn.exe&amp;quot;&lt;/span&gt; -Vr WebDev.WebHost.dll

&lt;span class="rem"&gt;rem Install into GAC, forcing overriding any existing assembly&lt;/span&gt;
&lt;span class="str"&gt;&amp;quot;%SDKHOME%\bin\gacutil.exe&amp;quot;&lt;/span&gt; /i WebDev.WebHost.dll /f&lt;/pre&gt;

&lt;h4&gt;Enjoy!&lt;/h4&gt;

&lt;p&gt;After patching and reinstalling the WebDev.WebHost.dll, hitting F5 in VS to launch your webapplication allows you to access the Webserver using any local IP address and thus allows tools like Fiddler to capture the traffic.&lt;/p&gt;

&lt;p&gt;Hint: You can also make your life easier by registering the Webserver in the context menu of any folder. Just use the registry script below:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Directory\shell\webdev.webserver.9]
@=&lt;span class="str"&gt;&amp;quot;ASP.NET Webserver 2008&amp;quot;&lt;/span&gt;

[HKEY_CLASSES_ROOT\Directory\shell\webdev.webserver.9\command]
@=&lt;span class="str"&gt;&amp;quot;\&amp;quot;&lt;/span&gt;C:\\Program Files\\Common Files\\Microsoft Shared\\DevServer\\9.0\\WebDev.WebServer.EXE\&lt;span class="str"&gt;&amp;quot;  /port:81 /vpath:\&amp;quot;&lt;/span&gt;/\&lt;span class="str"&gt;&amp;quot; /path:\&amp;quot;&lt;/span&gt;%1\&lt;span class="str"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;This allows you to launch the Webserver using a rightclick of your mouse on any arbitrary folder:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/SyCv0RCV0gI/AAAAAAAAB3I/IgrPwuOim-I/s1600-h/image%5B3%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://lh6.ggpht.com/_NxkvYPY_Msg/SyCv1J79YMI/AAAAAAAAB3M/Y5hUBydvy9M/image_thumb%5B1%5D.png?imgmax=800" width="355" height="177" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-5200949625513709600?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/5200949625513709600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=5200949625513709600' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/5200949625513709600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/5200949625513709600'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/sniff-http-traffic-with-aspnet.html' title='Sniff HTTP traffic with ASP.NET Development Webserver'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_NxkvYPY_Msg/SyCv1J79YMI/AAAAAAAAB3M/Y5hUBydvy9M/s72-c/image_thumb%5B1%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-7193029917654623481</id><published>2009-12-08T13:31:00.001+01:00</published><updated>2009-12-08T13:31:36.216+01:00</updated><title type='text'>Have a cup of coffee with a friend</title><content type='html'>&lt;p&gt;A friend recently told me a great story about priorities in your life. Not directly related to software development, I still think it might apply to one or another and I simply like this story very much. When things in your life seem almost too much to handle, when 24 hours in a day just are not enough, remember the mayonnaise jar and 2 cups of coffee.&lt;/p&gt;  &lt;p&gt;A professor stood before his philosophy class and had some items in front of him. When the class began, wordlessly, he picked up the very large, empty mayonnaise jar and proceeded to fill it with golf balls.   &lt;br /&gt;When no more golf balls would fit in the jar he asked the students if the jar was full. They agreed it was full.    &lt;br /&gt;    &lt;br /&gt;Then the professor picked up a box of pebbles and poured them into the jar. He shook the jar lightly. The pebbles rolled into open areas between the golf balls. He asked his students again if the jar was full. They agreed it was.    &lt;br /&gt;    &lt;br /&gt;The professor next picked up a box of sand and poured it into the jar. The sand filled up everything else. He once more asked the students if the jar was full. The students responded with a unanimous &amp;quot;yes&amp;quot;.    &lt;br /&gt;    &lt;br /&gt;The professor then produced two cups of coffee from under the table. He poured the coffee into the jar, effectively filling the empty spaces between the sand. The students laughed.    &lt;br /&gt;    &lt;br /&gt;&amp;quot;Now&amp;quot; said the professor, as the laughter subsided, &amp;quot;I want you to recognize that this jar represents your life. The Golf balls are the important things - God, Family, Children, Health, Friends, Passions - things that if everything else was lost and only they remained, your life would still be full. The pebbles are other things that matter - like your Job, House, Car, etc. The sand is everything else - the small stuff. If you put the sand in the jar first,&amp;quot; he continued, &amp;quot;There is no room for the pebbles or the golf balls. The same is true for life. If you spend all your time and energy on the small stuff, you will never have room for the things that are important to you.    &lt;br /&gt;    &lt;br /&gt;So pay attention to the things that are critical to your happiness. Play with your children. Take time to get that check-up. Take your partner out to dinner. Play another 18 holes. There will always be time to clean the house and fix the disposal. Take care of the golf balls first - the things that really matter. Set your priorities. The rest is just sand.&amp;quot;    &lt;br /&gt;    &lt;br /&gt;One of the students raised her hand and asked what the coffee represented. The professor smiled. &amp;quot;I am glad you asked. It just goes to show that no matter how full your life may seem, there's always room for a couple cups of coffee with friends.&amp;quot;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-7193029917654623481?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/7193029917654623481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=7193029917654623481' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/7193029917654623481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/7193029917654623481'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/12/have-cup-of-coffee-with-friend.html' title='Have a cup of coffee with a friend'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-7057058878850817714</id><published>2009-10-29T19:45:00.001+01:00</published><updated>2009-10-29T20:19:05.866+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrent'/><title type='text'>Parallelism for the Masses?</title><content type='html'>&lt;p&gt;I just returned from an interesting full-day &lt;a href="http://www.pc-ware.com/pcw/no/no/events/detaljer/event-9.htm" target="_blank"&gt;seminar on parallelizing applications&lt;/a&gt; using Intel's tool suite with the quite ambitous title &amp;quot;How to write bug free and performance optimized parallel (threaded ) applications ( Turning a serial into a parallel application)&amp;quot;. A demonstration of the capabilities of Intel Parallel Studio was quite impressive. &lt;/p&gt;  &lt;h5&gt;Clever Tools&lt;/h5&gt;  &lt;p&gt;Let Parallel Studio analyze your C/C++ code to detect performance hotspots and parallelizable code fragments. Then use OpenMP and add #pragma directives to actually &amp;quot;annotate&amp;quot; your code with parallelization hints for the compiler:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="preproc"&gt;#pragma&lt;/span&gt; omp parallel &lt;span class="kwrd"&gt;for&lt;/span&gt; reduction(+: sum) 
&lt;span class="kwrd"&gt;for&lt;/span&gt; (i = 0; i &amp;lt; 1000000; i++) { 
 sum = CalcSum(i, sum); 
}&lt;/pre&gt;

&lt;p&gt;Pretty neat, isn't it? I found it quite surprising how far one can already get nowadays by just using clever tools for (semi-)automatic parallelization of applications. Still: Can you prove the above code does not cause semantic errors? Remove the &amp;quot;for reduction(+: sum)&amp;quot; from the above and you will get a random results. &lt;/p&gt;

&lt;h5&gt;Required: a radically new approach&lt;/h5&gt;

&lt;p&gt;Introducing technlogies like OpenMP (or the new &lt;a href="http://msdn.microsoft.com/en-us/library/dd460693%28VS.100%29.aspx" target="_blank"&gt;.NET Parallel Programming libraries&lt;/a&gt; to mention a more recent one) doesn't help much to really improve the situation. It is like fixing&amp;#160; your bathroom with duct tape. It works - but it is not a sustainable solution. In my opinion, going parallel - and thus make your code scalable, be it on multi-core or a service in the cloud - requires more than tools. Everyone, who has already written one piece of multithreaded code, also has already had to debug a concurrency issue. It doesn't matter, how good you are, how much or little experience you have.&lt;/p&gt;

&lt;h5&gt;Actors enter the future stage&lt;/h5&gt;

&lt;p&gt;What does it take to write better scalable and parallelizable code? The problem with parallel code is &amp;quot;shared state&amp;quot;. Message Passing avoids this problem. The &lt;a href="http://en.wikipedia.org/wiki/Actor_model" target="_blank"&gt;Actor Programming Model&lt;/a&gt; takes this even further. Systems like Erlang have a long history in successfully applying this totally different programming paradigm (at least totally different from today's mainstream only of course). Multicore processors and cloud computing revived this paradigm by increasing the need for parallel programming support. &lt;a href="http://msdn.microsoft.com/en-us/devlabs/dd795202.aspx" target="_blank"&gt;Microsoft's Axum&lt;/a&gt; and attempts like the &lt;a href="http://xcoappspace.codeplex.com/" target="_blank"&gt;&amp;quot;XCoordination Application Space&amp;quot;&lt;/a&gt; try to bring this paradigm to the masses on the .NET platform, &lt;a href="http://www.scala-lang.org/node/242" target="_blank"&gt;Scala&lt;/a&gt; will likely be the next success on the Java platform (imho ironically by replacing the Java language on the JMV). I dare to predict, that lot of our programming future will be Actor-based. And the platform that makes implementing actors most convenient has good chances to become the next mainstream.&lt;/p&gt;

&lt;p&gt;What are your thoughts on the future of programming? How will we handle challenges like debugging or orchestration of actor communication in this new world? Keen to hear your opinions and/or experiences!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-7057058878850817714?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/7057058878850817714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=7057058878850817714' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/7057058878850817714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/7057058878850817714'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/10/parallelism-for-masses.html' title='Parallelism for the Masses?'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-8683635264801041503</id><published>2009-10-20T17:49:00.001+02:00</published><updated>2009-10-20T17:49:54.834+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='eda'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='soa'/><title type='text'>What Software Architects can learn from History - a conceptual look at SOA and EDA</title><content type='html'>&lt;p&gt;This blog post was inspired by the article &amp;quot;&lt;a href="http://msdn.microsoft.com/en-us/architecture/aa699424.aspx" target="_blank"&gt;SOA through the looking glass&lt;/a&gt;&amp;quot; by Udi Dahan, recently published in the MSDN Architecture Journal and a following discussion with collegues. One thing that quickly popped up was the different understandings of the terms SOA and EDA (we really should care about our own ubiquitous engineering language first ...). Here are my thoughts on Services, Events and why I think those concepts allow us to build better solutions, thus better meeting business needs, which is - after all - what we build all applications for.&lt;/p&gt;  &lt;h3&gt;How Lou Gerstner got IBM to dance&lt;/h3&gt;  &lt;p&gt;I do remember times where a big monolithic enterprise called IBM acted like a centralized mainframe in the market all over the world. Due to its organizational structure the company wasn't able to respond to new and changing market challenges within a reasonable timeframe. So why does IBM still exist? Because in the early 90s Lou Gerstner decided to restructure the whole company and split it into lots of small, autonomous profit centers (&amp;quot;&lt;a href="http://www.forbes.com/2002/11/11/cx_ld_1112gerstner.html"&gt;How Lou Gerstner got IBM to dance&lt;/a&gt;&amp;quot;). Those profit centers act like small companies embedded within a large company, being responsible for their own revenue as well as finding the right partners to connect with both within as well as outside the enterprise, while being able to leverage synergy effects from being part of a large enterprise. As a matter of fact, companies like Amazon and Google are such effective market players because they are organized exactly this way - service oriented. Service Orientation is a quite natural concept describing a set of autonomous actors collaborating with each other, exchanging information by sending messages and reacting to external stimuli, also known as events. In his article, Udi Dahan correctly points out that service orientation and events are just 2 sides of the same coin.&lt;/p&gt;  &lt;h3&gt;The world doesn't block because you have a coffee&lt;/h3&gt;  &lt;p&gt;In contrast to an all-to-common misconception, I do not see SOA and EDA as technologies. In fact both describe organizational and structural concepts that apply to business organizations in the first place. Thus I see SOA and EDA as a way to translate those natural concepts onto the way we build software. Instead of relying on leaky abstractions like synchronous remote method calls (crossing process boundaries may always fail for hundreds of possible reasons) and distributed transactions (what if something goes wrong during the commit-phase??), software engineers need to take a good look at how the world really works that they are trying to project into bits and bytes. If you look at the real world, it doesn't use 2-phase-commit. Instead it uses compensation actions (see Greg Hohpes awarded article &amp;quot;&lt;a href="http://www.eaipatterns.com/ramblings/18_starbucks.html"&gt;Starbucks does not use 2-phase-commit&lt;/a&gt;&amp;quot;. Also the real world seldom uses synchronous commands. Instead we send messages and react on events when they occur. You don't get blocked when you receive an email - instead it is up to you to decide when to come back and read it later. Also the sender is not blocked from her work, waiting for response from you. The real worlds acts sometimes sequentially (you receive the email before you can answer it), but seldom synchronous. You might have forgotten to pay a bill? You will receive a friendly reminder letter and if that overlaps with the fact that you already paid the bill in the meantime, it will state to &amp;quot;safely ignore this letter&amp;quot; in this case. How does the real world stay agile and responsive? Use small groups of people concentrating on a particular responsibility instead of large monolithic blocks responsible for everything, effectively achieving nothing.&lt;/p&gt;  &lt;h3&gt;Business Partners do not share database schemata&lt;/h3&gt;  &lt;p&gt;What is important about the word &amp;quot;autonomous&amp;quot;? I see the importance in the evolvability and flexibility of a system. Companies do not simply change their interfaces to partners they collaborate with. And 2 collaborating companies do seldom use a shared database, they will even use different fields for their &amp;quot;customer&amp;quot; datastructure. Here is where I see the &amp;quot;&lt;a href="http://dddstepbystep.com/wikis/ddd/bounded-context.aspx"&gt;Bounded Contexts&lt;/a&gt;&amp;quot; first described by Eric Evans coming into play. Instead of falling into the trap of the anti-patterns &amp;quot;shared database&amp;quot; and &amp;quot;shared datastructure&amp;quot;, where one single dataschema/-structure tries to please several different needs, split e.g. editing information like your personal profile on facebook from searching the whole user database for a particular name. Those are different taks, requiring datastructures and processes optimized for that particular task. Sharing a database does not work in this case not only because of the size of facebooks userdatabase, but also because changes to to either of the tasks would become impossible. Instead of achieving simplicity in the database schema, one introduces complexity in the evolvability of a system because of strong dependencies between components due to shared structures (&lt;a href="http://www.agiledata.org/essays/oneTruth.html"&gt;&amp;quot;The 'One Truth Above All Else' Anti-Pattern&amp;quot;&lt;/a&gt;).&lt;/p&gt;  &lt;h3&gt;Cloud Computing requires us to take new look&lt;/h3&gt;  &lt;p&gt;Traditional software development strategies hit the wall even faster when it comes to develop solutions to run in the cloud. As Gianpaolo Carraro describes in his blog post &lt;a href="http://blogs.msdn.com/gianpaolo/archive/2008/10/15/head-in-the-cloud-feet-on-the-ground-an-article-about-the-cloud.aspx" target="_blank"&gt;&amp;quot;Head in the Cloud, Feet on the Ground&lt;/a&gt;&amp;quot; (and in &lt;a href="http://msdn.microsoft.com/en-us/architecture/dd129910.aspx" target="_blank"&gt;MSDN Architecture Journal #17&lt;/a&gt;), business demands will sooner or later likely force us to move at least parts of the systems we build into a cloud environment. How do you build a system, where service instances may come and go as needed? Where services simply move from one box to another without prior notice, controlled by the cloud operating system? Aside from other important implications, simple conventional synchronous method calls do not work anymore in such an environment. Different strategies are needed and service-orientation, asynchronously sent messages and reacting to events are part of the solution, leading to a system of collaborating services, talking to each other in &lt;a href="http://www.infoq.com/presentations/hohpe-soa-conversations" target="_blank"&gt;conversations&lt;/a&gt;.&lt;/p&gt;  &lt;h3&gt;It's always about balance&lt;/h3&gt;  &lt;p&gt;Of course building a software following those principles also means, that you pull all those previously hidden complexities to the surface and into your application domain instead of leaving them up to the infrastructure layer, where they stay buried until something goes wrong and they bites you from the back. Thus one has to make a careful decision, where it is ok to use easy to write synchronous remote calls and accept the (hidden) risk of lack of scalability and blocking callers due to a broken infrastructure, eating up webserver resources, while blocking calls pile up instead of making this fact explicit in the organizational structure of an application system, partitioning functionality into several autonomous services, collaborating with each other by sending messages and reacting to events. As usual, it is a matter of compromise and finding the right balance. You just need to be aware of the risks you accept when synchronously calling a webservice method using SOAP over HTTP in favour of having to write a simple method call vs. the explicit and therefore more complex communication patterns happening between application components, but providing better flexibility and scalability due to higher decoupling.&lt;/p&gt;  &lt;h3&gt;We've already been there&lt;/h3&gt;  &lt;p&gt;Those ideas are not new. IBM's restructuring is just one of the examples taken from reality. Even within the Software Engineering industrie those ideas have been around for quite a while and most of us even already used them. Probably not everyone is writing programs in Erlang, which is quite successful in applying those ideas since the 60s. But almost everyone has written GUI applications, haven't we? Well, there is this thing called &amp;quot;Window Message Queue&amp;quot; and a technique called &amp;quot;reacting to user events&amp;quot;. It is time to undust this knowledge. Although IT history is rather short compared to other industries, Architects should learn from it.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-8683635264801041503?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/8683635264801041503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=8683635264801041503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/8683635264801041503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/8683635264801041503'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/10/what-software-architects-can-learn-from.html' title='What Software Architects can learn from History - a conceptual look at SOA and EDA'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-3897424377030952659</id><published>2009-08-06T20:36:00.001+02:00</published><updated>2009-08-07T01:18:41.006+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='spring'/><category scheme='http://www.blogger.com/atom/ns#' term='ioc'/><title type='text'>Spring for .NET 1.3.0 Release Candidate available</title><content type='html'>&lt;p&gt;Finally we made it: The next release of Spring for .NET is available for preview and brings a couple of new things as well as over 100 fixed bugs to the table. Grab the new release as usual from our website &lt;a href="http://www.springframework.net"&gt;http://www.springframework.net&lt;/a&gt; and give it a test run. The final release is currently scheduled for the first week in September. Below I will give you a short introduction to the new features.&lt;/p&gt;  &lt;h4&gt;New Features&lt;/h4&gt;  &lt;h5&gt;NVelocity Support&lt;/h5&gt;  &lt;p&gt;Erez Mazor joined the team in June and brought a nice integration of the &lt;a href="http://www.castleproject.org/others/nvelocity/index.html" target="_blank"&gt;NVelocity template library&lt;/a&gt; (part of the Castle project) with him. Let's asume you need to send a confirmation email after processing T-Shirt order to a customer. Most of this email will come from a template, just a few variables will be individual for each customer. Here's how such a template looks like using the Velocity Template Language:&lt;span class="lnum"&gt;&amp;#160; &lt;/span&gt;&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre&gt;Dear#if ($sex == &amp;quot;F&amp;quot;) Ms#else Mr#end $recipient,&lt;/pre&gt;

  &lt;pre&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;We are happy to withdraw $1Mio from your account&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Here's an example on how to use Spring.NET's integration to send an Email from your application. The configuration causes the NVelocityFactory to load templates from the NVelocityDemo assembly's &amp;quot;NVelocityDemo&amp;quot; namespace:&lt;/p&gt;

&lt;div class="csharpcode"&gt;
  &lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;objects&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.springframework.net&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;xmlns:nv&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://www.springframework.net/nvelocity&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;  &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;nv:engine&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;velocityEngine&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;    &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;nv:resource-loader&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;      &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;nv:spring&lt;/span&gt; &lt;span class="attr"&gt;uri&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;assembly://NVelocityDemo/NVelocityDemo/&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;    &amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;nv:resource-loader&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;  &amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;nv:engine&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt; &lt;span class="attr"&gt;id&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;emailSendService&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;NVelocityDemo.EmailSendService&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;property&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;VelocityEngine&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;ref&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;velocityEngine&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;object&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;objects&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Here's the C# Code of my EmailSendService class:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; EmailSendService
{
  &lt;span class="kwrd"&gt;public&lt;/span&gt; VelocityEngine VelocityEngine { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SendEmail(&lt;span class="kwrd"&gt;string&lt;/span&gt; recipientName, &lt;span class="kwrd"&gt;string&lt;/span&gt; sex, &lt;span class="kwrd"&gt;string&lt;/span&gt; emailAddress, &lt;span class="kwrd"&gt;string&lt;/span&gt; subject)
  {
    Hashtable model = &lt;span class="kwrd"&gt;new&lt;/span&gt; Hashtable();
    model[&lt;span class="str"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;] = emailAddress;
    model[&lt;span class="str"&gt;&amp;quot;recipient&amp;quot;&lt;/span&gt;] = recipientName;
    model[&lt;span class="str"&gt;&amp;quot;sex&amp;quot;&lt;/span&gt;] = sex;
    IContext modelContext = &lt;span class="kwrd"&gt;new&lt;/span&gt; VelocityContext(model);
    StringWriter sw = &lt;span class="kwrd"&gt;new&lt;/span&gt; StringWriter();
    &lt;span class="kwrd"&gt;this&lt;/span&gt;.VelocityEngine.MergeTemplate(&lt;span class="str"&gt;&amp;quot;confirmationEmail.vm&amp;quot;&lt;/span&gt;, Encoding.UTF8.HeaderName, modelContext, sw);

    &lt;span class="kwrd"&gt;string&lt;/span&gt; emailContent = sw.ToString();

    &lt;span class="rem"&gt;// send mail&lt;/span&gt;
    Console.WriteLine(&lt;span class="str"&gt;&amp;quot;Sending email to {0} with subject '{1}':\n{2}&amp;quot;&lt;/span&gt;, emailAddress, subject, emailContent);
  }
}&lt;/pre&gt;

&lt;p&gt;Running this example will inform our customer about our pricing for T-Shirts: &lt;/p&gt;

&lt;pre class="csharpcode"&gt;Sending email to foo@world.com with subject &lt;span class="str"&gt;'Thank you!'&lt;/span&gt;:
Dear Mr Smith,

we are happy to withdraw $1Mio from your account&lt;/pre&gt;

&lt;h5&gt;TIBCO Enterprise Message Service&lt;/h5&gt;

&lt;p&gt;Similar to our support for MSMQ and ActiveMQ, consequently there is now also support for Tibco's EMS. If you are already familiar with Spring's ActiveMQ support, you will quickly feel comfortable. To get started, check out our &lt;a href="http://www.springframework.net/docs/1.3.0-RC1/reference/html/messaging.html" target="_blank"&gt;reference documentation&lt;/a&gt; and the upcoming blog post at &lt;a href="http://blog.springsource.com/author/mpollack/" target="_blank"&gt;Mark Pollack's Blog&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;MS Test&lt;/h5&gt;

&lt;p&gt;Some of us are forced to write their unit tests using Microsoft's own testing framework. To support them, Spring.NET now also integrates support for writing unit and integration tests similar to the one already available for NUnit. You can find the supporting stuff in the &lt;a href="http://www.springframework.net/docs/1.3.0-RC1/api/net-2.0/html/Spring.Testing.Microsoft~Spring.Testing.Microsoft.html" target="_blank"&gt;Spring.Testing.Microsoft assembly&lt;/a&gt;. &lt;/p&gt;

&lt;h4&gt;Noteworthy Improvements&lt;/h4&gt;

&lt;h5&gt;Testing&lt;/h5&gt;

&lt;p&gt;In response to a lot of requests, we upgraded our NUnit testing environment to the latest NUnit 2.5.1. There is also new support for writing database integration tests. Use the &lt;a href="http://www.springframework.net/docs/1.3.0-RC1/api/net-2.0/html/Spring.Testing.NUnit~Spring.Testing.Ado.SimpleAdoTestUtils~Members.html" target="_blank"&gt;SimpleAdoTestUtils class&lt;/a&gt; to execute arbitrary SQL scripts to setup/teardown your database. An example is Spring's NHibernate Integration tests. Here is the SQL script to recreate our integration database:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;IF&lt;/span&gt;  &lt;span class="kwrd"&gt;EXISTS&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; name &lt;span class="kwrd"&gt;FROM&lt;/span&gt; sys.databases &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; name = N&lt;span class="str"&gt;'Spring'&lt;/span&gt;)
&lt;span class="kwrd"&gt;BEGIN&lt;/span&gt;
    &lt;span class="kwrd"&gt;ALTER&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; Spring 
        &lt;span class="kwrd"&gt;SET&lt;/span&gt; SINGLE_USER 
        &lt;span class="kwrd"&gt;WITH&lt;/span&gt; &lt;span class="kwrd"&gt;ROLLBACK&lt;/span&gt; &lt;span class="kwrd"&gt;IMMEDIATE&lt;/span&gt;

    &lt;span class="kwrd"&gt;DROP&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; Spring
&lt;span class="kwrd"&gt;END&lt;/span&gt;
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="kwrd"&gt;IF&lt;/span&gt;  &lt;span class="kwrd"&gt;EXISTS&lt;/span&gt; (&lt;span class="kwrd"&gt;SELECT&lt;/span&gt; * &lt;span class="kwrd"&gt;FROM&lt;/span&gt; sys.server_principals &lt;span class="kwrd"&gt;WHERE&lt;/span&gt; name = N&lt;span class="str"&gt;'springqa2'&lt;/span&gt;)
    &lt;span class="kwrd"&gt;DROP&lt;/span&gt; LOGIN [springqa2]
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;DATABASE&lt;/span&gt; Spring
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; LOGIN [springqa2] &lt;span class="kwrd"&gt;WITH&lt;/span&gt; PASSWORD=N&lt;span class="str"&gt;'springqa2'&lt;/span&gt;, DEFAULT_DATABASE=[Spring], DEFAULT_LANGUAGE=[us_english]
&lt;span class="kwrd"&gt;GO&lt;/span&gt;

&lt;span class="kwrd"&gt;USE&lt;/span&gt; Spring
&lt;span class="kwrd"&gt;CREATE&lt;/span&gt; &lt;span class="kwrd"&gt;USER&lt;/span&gt; [springqa2] &lt;span class="kwrd"&gt;FOR&lt;/span&gt; LOGIN [springqa2] &lt;span class="kwrd"&gt;WITH&lt;/span&gt; DEFAULT_SCHEMA=[dbo]
&lt;span class="kwrd"&gt;EXEC&lt;/span&gt; sp_addrolemember &lt;span class="str"&gt;'db_owner'&lt;/span&gt;, &lt;span class="str"&gt;'springqa2'&lt;/span&gt;
&lt;span class="kwrd"&gt;GO&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Now, leveraging &lt;a href="http://www.nunit.org/index.php?p=setupFixture&amp;amp;r=2.4" target="_blank"&gt;NUnit's [SetupFixture] feature&lt;/a&gt;, we can easily execute this and other scripts before the execution of each fixture:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;[SetUpFixture]
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Setup
{
  &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;const&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; DBConnection = &lt;span class="str"&gt;&amp;quot;Data Source=SPRINGQA;Database=$DATABASE$;Trusted_Connection=False;User ID=springqa;Password=springqa&amp;quot;&lt;/span&gt;;
  &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; IResourceLoader resourceLoader = &lt;span class="kwrd"&gt;new&lt;/span&gt; ConfigurableResourceLoader();

  &lt;span class="kwrd"&gt;private&lt;/span&gt; IResource GetResource(&lt;span class="kwrd"&gt;object&lt;/span&gt; instance, &lt;span class="kwrd"&gt;string&lt;/span&gt; name)
  {
    &lt;span class="kwrd"&gt;string&lt;/span&gt; resourcePath = TestResourceLoader.GetAssemblyResourceUri(instance, name);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; resourceLoader.GetResource(resourcePath);
  }

  [SetUp]
  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; InstallMSSQLDatabase()
  {
    IDbProvider dbProvider = DbProviderFactory.GetDbProvider(&lt;span class="str"&gt;&amp;quot;SqlServer-2.0&amp;quot;&lt;/span&gt;);
    AdoTemplate ado = &lt;span class="kwrd"&gt;new&lt;/span&gt; AdoTemplate(dbProvider);

    &lt;span class="rem"&gt;// (re-)create database(s)&lt;/span&gt;
    dbProvider.ConnectionString = DBConnection.Replace(&lt;span class="str"&gt;&amp;quot;$DATABASE$&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;master&amp;quot;&lt;/span&gt;);
    SimpleAdoTestUtils.ExecuteSqlScript(ado, GetResource(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;RecreateDatabases.sql&amp;quot;&lt;/span&gt;));

    &lt;span class="rem"&gt;// create tables&lt;/span&gt;
    dbProvider.ConnectionString = DBConnection.Replace(&lt;span class="str"&gt;&amp;quot;$DATABASE$&amp;quot;&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Spring&amp;quot;&lt;/span&gt;);
    SimpleAdoTestUtils.ExecuteSqlScript(ado, GetResource(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Data.NHibernate/creditdebit.sql&amp;quot;&lt;/span&gt;));
    SimpleAdoTestUtils.ExecuteSqlScript(ado, GetResource(&lt;span class="kwrd"&gt;this&lt;/span&gt;, &lt;span class="str"&gt;&amp;quot;Data.NHibernate/testObject.sql&amp;quot;&lt;/span&gt;));
  }
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Using the new NVelocity integration, you could even easily parameterize your SQL scripts for different environments.&lt;/p&gt;

&lt;h5&gt;Configuration Error Handling &lt;/h5&gt;

&lt;p&gt;Previously sometimes it was hard to read configuration errors. I put some effort into reducing this pain and make the error messages much more explicit. Now you get the exact filename + linenumber of the offending object definition and also a more detailled explanation, what is causing the problem.&lt;/p&gt;

&lt;h5&gt;AOP Performance&lt;/h5&gt;

&lt;p&gt;The performance of AOP proxies at runtime improved, but also *creating* such singleton proxies at startup time could cause some issues. You now get a bunch of different &lt;a href="http://www.springframework.net/doc-latest/reference/html/aop.html#aop-autoproxy" target="_blank"&gt;Auto-Proxy processor implementations&lt;/a&gt; to choose from to better suite your exact needs. &lt;/p&gt;

&lt;p&gt;Sometimes using &amp;lt;tx:attribute-driven /&amp;gt; or &amp;lt;aop:config&amp;gt; could &lt;a href="http://forum.springframework.net/showthread.php?t=5528" target="_blank"&gt;cause issues&lt;/a&gt; when an additional XXXAutoProxyCreator was defined in your configuration. This roots in the fact that those 2 configuration elements silently registered their own DefaultAutoProxyCreator under the hoods. This is now taken care of and it is guaranteed that infrastructure AOP elements will not interfere with user-defined ones anymore.&lt;/p&gt;

&lt;h4&gt;Feedback welcome&lt;/h4&gt;

&lt;p&gt;The release will be in ~ 3-4 weeks, so please grab a copy of the release candidate and give it a whirl - We'd be happy to get your &lt;a href="http://forum.springframework.net/" target="_blank"&gt;feedback&lt;/a&gt;!&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-3897424377030952659?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/3897424377030952659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=3897424377030952659' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/3897424377030952659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/3897424377030952659'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/08/spring-for-net-130-release-candidate.html' title='Spring for .NET 1.3.0 Release Candidate available'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-6858942921545004514</id><published>2009-05-04T11:33:00.003+02:00</published><updated>2009-05-12T12:52:48.211+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><title type='text'>Common Logging 2.0 for .NET Released</title><content type='html'>&lt;p&gt;Last week I released a new version of Common Logging 2.0 for the .NET platform. You can get the &lt;a href="http://netcommon.sourceforge.net/downloads.html" target="_blank"&gt;distribution&lt;/a&gt; as well as online &lt;a href="http://netcommon.sourceforge.net/docs/2.0.0/api/html/index.html" target="_blank"&gt;API&lt;/a&gt; and &lt;a href="http://netcommon.sourceforge.net/docs/2.0.0/reference/html/index.html" target="_blank"&gt;User Reference&lt;/a&gt; documentation from the &lt;a href="http://netcommon.sourceforge.net/" target="_blank"&gt;project website&lt;/a&gt;. For users of previous versions there is also a &lt;a href="http://netcommon.sourceforge.net/docs/2.0.0/reference/html/ch01.html#d4e45" target="_blank"&gt;section about upgrading to 2.0&lt;/a&gt;.&lt;/p&gt; 
&lt;h4&gt;What is Common.Logging?&lt;/h4&gt; 
&lt;p&gt;Similar to Java's &lt;a href="http://commons.apache.org/logging/" target="_blank"&gt;Apache commons-logging&lt;/a&gt;, Common.Logging is an ultra-thin brigde between different .NET logging implementations based on original work done by the &lt;a href="http://ibatis.apache.org/" target="_blank"&gt;iBatis.NET&lt;/a&gt; team. A framework or library using Common.Logging can be used with any logging implementation at runtime and thus doesn't lock a user to a specific framework or worse letting him struggle with different frameworks using different logging implementations.&lt;/p&gt;  &lt;p&gt;&lt;img title="image" style="border: 0px none ; display: block; float: none; margin-left: auto; margin-right: auto;" alt="image" src="http://lh3.ggpht.com/_NxkvYPY_Msg/Sf65FXK_etI/AAAAAAAAACo/LyhT30xVknY/image_thumb%5B4%5D.png?imgmax=800" width="350" border="0" height="246" /&gt; &lt;/p&gt;  &lt;p&gt;Common.Logging comes with adapters for all popular logging implementations like log4net and Enterprise Library Logging.&lt;/p&gt; 

&lt;h4&gt;&lt;a name="#bridging"&gt;Bridging between logging implementations&lt;/a&gt;&lt;/h4&gt;

&lt;p&gt;You might run into the problem, that libraries used by your application use different logging implementations. Common.Logging allows you to route from those implementations into any logging system of your choice:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/Sf62aQBcZBI/AAAAAAAAACg/I1vRZmBcIcM/s1600-h/image%5B11%5D.png"&gt;&lt;img title="image" style="border-width: 0px; display: block; float: none; margin-left: auto; margin-right: auto;" alt="image" src="http://lh6.ggpht.com/_NxkvYPY_Msg/Sf62cWTuWvI/AAAAAAAAACk/PQxk0A7uSUQ/image_thumb%5B9%5D.png?imgmax=800" width="350" border="0" height="359" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Please see reference documentation for an example on how to &lt;a href="http://netcommon.sourceforge.net/docs/2.0.0/reference/html/ch01.html#d4e362" target="_blank"&gt;configure such a bridging scenario&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;What's new in 2.0?&lt;/h4&gt;  &lt;p&gt;Several extensions and improvements were made, namly&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Dropped .NET 1.1 Support &lt;/li&gt;    &lt;li&gt;Added support for Enterprise Library 4.1 Logging &lt;/li&gt;    &lt;li&gt;Extended and improved ILog Interface &lt;/li&gt;    &lt;li&gt;Convenience LogManager.GetCurrentClassLogger() Method &lt;/li&gt;   
&lt;li&gt;Bi-directional log event routing between logging implementations (see &lt;a href="http://www.blogger.com/post-edit.g?blogID=2486313360029846926&amp;amp;postID=6858942921545004514#bridging"&gt;&lt;b&gt;bridging&lt;/b&gt;&lt;/a&gt; above) &lt;/li&gt;   
&lt;li&gt;Improved performance &lt;/li&gt; &lt;/ul&gt; 
&lt;p&gt;I already blogged about &lt;a href="http://eeichinger.blogspot.com/2009/01/thoughts-on-systemdiagnostics-trace-vs.html" target="_blank"&gt;comparing Common.Logging performance to System.Diagnostics.Trace&lt;/a&gt;. According to a thread on stackoverflow, &lt;a href="http://stackoverflow.com/questions/201354/is-log4net-much-slower-than-system-diagnostics-trace" target="_blank"&gt;log4net seems even slower than System.Diagnostics.Trace&lt;/a&gt;.&lt;/p&gt;  &lt;h4&gt;Configuring Common.Logging&lt;/h4&gt;  &lt;p&gt;For examples on how to configure and use Common.Logging and bridge different logging implementations, please see the user refererence guide. The API documentation contains configuration and usage examples on each adapter implementation. Here is an example for configuring Common.Logging to write messages to the console:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sectionGroup&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="common"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;section&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;="logging"&lt;/span&gt;
            &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="Common.Logging.ConfigurationSectionHandler, Common.Logging"&lt;/span&gt;
            &lt;span class="attr"&gt;requirePermission&lt;/span&gt;&lt;span class="kwrd"&gt;="false"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;sectionGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;common&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;logging&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;factoryAdapter&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;="Common.Logging.Simple.ConsoleOutLoggerFactoryAdapter, Common.Logging"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;arg&lt;/span&gt; &lt;span class="attr"&gt;key&lt;/span&gt;&lt;span class="kwrd"&gt;="level"&lt;/span&gt; &lt;span class="attr"&gt;value&lt;/span&gt;&lt;span class="kwrd"&gt;="ALL"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
   &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;factoryAdapter&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;logging&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;common&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;h4&gt;Using Common.Logging&lt;/h4&gt;

&lt;p&gt;Using Common.Logging is as simple as shown below:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;ILog log = LogManager.GetCurrentClassLogger();
log.DebugFormat(&lt;span class="str"&gt;"Hi {0}"&lt;/span&gt;, &lt;span class="str"&gt;"dude"&lt;/span&gt;);&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;Hint: &lt;/b&gt;When using NET 3.5, you can leverage lambda syntax for logging to avoid any performance penalties:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;log.Debug( m=&amp;gt;m(&lt;span class="str"&gt;"value= {0}"&lt;/span&gt;, obj.ExpensiveToCalculateInformation()) );&lt;/pre&gt;

&lt;p&gt;This is the equivalent to writing &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (log.IsDebugEnabled)
{
 log.Debug(&lt;span class="str"&gt;"value={0}"&lt;/span&gt;, obj.ExpensiveToCalculateInformation());
}&lt;/pre&gt;

&lt;p&gt;and ensures that you don't have to pay for calculating the debug information message in case level "Debug" is disabled.&lt;/p&gt;

&lt;h4&gt;Further Roadmap&lt;/h4&gt;

&lt;p&gt;The following features and improvements are planned for the next release, some of them already in the works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partial Trust compliance (already in the trunk) &lt;/li&gt;

&lt;li&gt;Support for Windows Azure &lt;/li&gt;

&lt;li&gt;Support for Silverlight &lt;/li&gt;

&lt;li&gt;Logging (aka 'Trace') Context support (in progress) see &lt;a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.correlationmanager.startlogicaloperation.aspx" target="_blank"&gt;System.Diagnostics.CorrelationManager&lt;/a&gt; and &lt;a href="http://logging.apache.org/log4net/release/manual/contexts.html" target="_blank"&gt;log4net contexts&lt;/a&gt; for examples &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course I would like to invite you to &lt;a href="https://sourceforge.net/tracker/?group_id=182424" target="_blank"&gt;submit any feature request, bug reports or other improvement suggestions&lt;/a&gt; to the project's issue tracker.&lt;/p&gt;

&lt;p&gt;Happy logging!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-6858942921545004514?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/6858942921545004514/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=6858942921545004514' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6858942921545004514'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/6858942921545004514'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/05/common-logging-20-for-net-released.html' title='Common Logging 2.0 for .NET Released'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh3.ggpht.com/_NxkvYPY_Msg/Sf65FXK_etI/AAAAAAAAACo/LyhT30xVknY/s72-c/image_thumb%5B4%5D.png?imgmax=800' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-2097194046251408793</id><published>2009-04-17T10:40:00.001+02:00</published><updated>2009-04-17T10:55:25.996+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ioc'/><title type='text'>IoC != Resolve&lt;&gt;()</title><content type='html'>&lt;p&gt;Thanks to &lt;a href="http://startbigthinksmall.wordpress.com/" target="_blank"&gt;Lars Corneliussen&lt;/a&gt;, I just ran across the new &lt;a href="http://code.google.com/p/scotaltdotnet/" target="_blank"&gt;Horn Package Manager&lt;/a&gt;, promising a Maven-like automatic resolution of package dependencies to allow you building a whole OSS stack from scratch.&lt;/p&gt;  &lt;p&gt;Not directly related to horn, but on &lt;a href="http://thesoftwaresimpleton.blogspot.com/2009/03/horn-architecure-overview.html" target="_blank"&gt;horn architecture introduction&lt;/a&gt; I read:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh4.ggpht.com/_NxkvYPY_Msg/SehCjT5WsdI/AAAAAAAAACY/r4m51r_2kms/s1600-h/image%5B7%5D.png"&gt;&lt;img title="image" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="110" alt="image" src="http://lh4.ggpht.com/_NxkvYPY_Msg/SehCjudl-II/AAAAAAAAACc/QONvKWDySPc/image_thumb%5B3%5D.png?imgmax=800" width="644" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Talking about Inversion of Control and showing a ServiceLocator - even worse: a static one (!) - piece of code always makes me &lt;em&gt;very&lt;/em&gt; nervous. Imho SL is one of the worst patterns ever because it claims to be IoC, but still couples your code to the container - or at least the SL. I always wondered, why People keep asking for extended ServiceLocator-style support in Spring.NET - such bad examples are one of the major reasons I guess. &lt;/p&gt;  &lt;p&gt;There has also been quite some talk about &lt;a href="http://www.codeplex.com/CommonServiceLocator" target="_blank"&gt;CommonServiceLocator&lt;/a&gt; as a means to make the container interchangable. &lt;a href="http://blog.springsource.com/2008/10/03/the-common-service-locator-library/" target="_blank"&gt;Mark Pollack&lt;/a&gt;, &lt;a href="http://ayende.com/Blog/archive/2008/10/02/the-common-service-locator-library.aspx" target="_blank"&gt;Ayende&lt;/a&gt; and others (like &lt;a href="http://abdullin.com/journal/2008/10/12/common-ioc-denominator-for-autofac-castle-and-unity-net-cont.html" target="_blank"&gt;Rinat Abdullin&lt;/a&gt;)&amp;#160; posted statements what CommonServiceLocator is for and what it is not.&lt;/p&gt;  &lt;p&gt;Dear developers out there: IoC is about removing dependencies from your code, not replacing them with new ones!&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;P.S: NTL, horn sounds interesting and I will definitely check it out ;-)&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-2097194046251408793?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/2097194046251408793/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=2097194046251408793' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/2097194046251408793'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/2097194046251408793'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/04/ioc-resolve.html' title='IoC != Resolve&amp;lt;&amp;gt;()'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_NxkvYPY_Msg/SehCjudl-II/AAAAAAAAACc/QONvKWDySPc/s72-c/image_thumb%5B3%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-5087568541917733970</id><published>2009-03-31T18:01:00.001+02:00</published><updated>2009-03-31T21:30:17.401+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ndoc3'/><title type='text'>NDoc is dead - long live NDoc3</title><content type='html'>&lt;p&gt;While working on the next release of the &lt;a href="http://netcommon.sourceforge.net/" target="_blank"&gt;Common.Logging&lt;/a&gt; library, I noticed that we didn't have an API documentation yet. On Spring.NET we use &lt;a href="http://www.innovasys.com/products/dx2008/overview.aspx" target="_blank"&gt;DocumentX&lt;/a&gt; (alas in the outdated version 2005) to generate the SDK documentation, thus I tried to set this up for Common.Logging. Quickly I faced some issues: First we do have a free Open Source project License for &lt;a href="http://www.springframework.net" target="_blank"&gt;Spring.NET&lt;/a&gt;, but I'm not sure, if I can reuse it for another framework. Second, you can't run DocX from the commandline (except when you explicitely ask Innovasys for it). This is a no-go for continuous integration.&lt;/p&gt;  &lt;h4&gt;Any Open Source Alternatives?&lt;/h4&gt;  &lt;p&gt;Looking for alternatives - as an OSS guy of course I prefer an OSS tool, I couldn't find much. Being burned a while ago by &lt;a href="http://msdn.microsoft.com/en-us/vstudio/bb608422.aspx" target="_blank"&gt;Sandcastle&lt;/a&gt; and very irritated about MSFTs seriousness on this tool, the only tool I could find and that was at least close to what I expected was &lt;a href="http://ndoc3.sourceforge.net" target="_blank"&gt;NDoc3&lt;/a&gt;. My expectations were low: I want to be able to integrate it in my build script and the documentation process should be tightly integrated with my daily development work. &lt;/p&gt;  &lt;h4&gt;Getting involved&lt;/h4&gt;  &lt;p&gt;Being the successor of my formerly beloved, but &lt;a href="http://www.charliedigital.com/PermaLink,guid,95b2ab68-ba92-413a-b758-2783cde5df9c.aspx" target="_blank"&gt;now dead, NDoc tool&lt;/a&gt;, thanks to &lt;a href="http://community.hydrussoftware.com/blogs/john/archive/2008/07/23/ndoc-2-0-is-not-quite-dead.aspx" target="_blank"&gt;Kim Christensen picking up the project&lt;/a&gt;, NDoc3 is capable of handling new .NET 2.0 features like generics, asymetric property accessibility etc.. For those familiar with NDoc, there won't be any surprises. Guides for using NDoc can e.g. be found &lt;a href="http://www.codeproject.com/KB/aspnet/NDoc.aspx" target="_blank"&gt;here&lt;/a&gt;. Being not 100% satisfied with it yet, I did what OSS is all about: I involved myself in the further development of NDoc3.&lt;/p&gt;  &lt;h4&gt;What's new?&lt;/h4&gt;  &lt;p&gt;After a week of hard work, I refactored the codebase to allow for better development in the future as well as better testing. In addition, I introduced a new feature: &lt;strong&gt;MergeAssemblies&lt;/strong&gt;. This means that similar to DocX, it is now possible to generate an extra hierarchy level for assemblies. By default, the flag is on, but you can turn it off:&lt;a href="http://lh5.ggpht.com/_NxkvYPY_Msg/SdI-MjSkwbI/AAAAAAAAAB4/GcGNKyBUEJg/s1600-h/image%5B18%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="256" alt="image" src="http://lh6.ggpht.com/_NxkvYPY_Msg/SdI-NQ1yb9I/AAAAAAAAAB8/l-JFG2QR-BQ/image_thumb%5B12%5D.png?imgmax=800" width="418" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This results in a navigation hierarchy created as shown below:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NxkvYPY_Msg/SdI-N9aIQTI/AAAAAAAAACA/7Ura6tPw1-8/s1600-h/image%5B19%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="199" alt="image" src="http://lh3.ggpht.com/_NxkvYPY_Msg/SdI-ODNIigI/AAAAAAAAACE/Ho_Hyny__iU/image_thumb%5B13%5D.png?imgmax=800" width="409" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;This also allows for yet another nice feature: the &lt;strong&gt;assembly overview &lt;/strong&gt;page. It provides a complete overview of your assembly's references, dependencies and all types. Here is an examples of how this looks like:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_NxkvYPY_Msg/SdI-OyY9GwI/AAAAAAAAACI/wKb4IMXO4Bk/s1600-h/image%5B24%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: block; border-left-width: 0px; float: none; border-bottom-width: 0px; margin-left: auto; margin-right: auto; border-right-width: 0px" height="926" alt="image" src="http://lh4.ggpht.com/_NxkvYPY_Msg/SdI-PjrzSxI/AAAAAAAAACM/bbhdanm9FO0/image_thumb%5B16%5D.png?imgmax=800" width="751" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;To allow for automatically generating the assembly summary text, I introduced a new AssemblyDoc class (similar to the NamespaceDoc feature). Just add a class named &lt;em&gt;AssemblyDoc&lt;/em&gt; to the global namespace in your assembly:&lt;/p&gt;  &lt;div class="csharpcode"&gt;   &lt;pre&gt;&lt;span class="lnum"&gt;   1:  &lt;/span&gt;&amp;#160;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   2:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   3:  &lt;/span&gt;&lt;span class="rem"&gt;/// This assembly contains the adapter to the &lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   4:  &lt;/span&gt;&lt;span class="rem"&gt;/// NLog 1.0.0.505 library&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   5:  &lt;/span&gt;&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   6:  &lt;/span&gt;&lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;sealed&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; AssemblyDoc&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   7:  &lt;/span&gt;{&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   8:  &lt;/span&gt;    &lt;span class="rem"&gt;// serves as assembly summary for NDoc3 (http://ndoc3.sourceforge.net)&lt;/span&gt;&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;   9:  &lt;/span&gt;    &lt;span class="kwrd"&gt;private&lt;/span&gt; AssemblyDoc()&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  10:  &lt;/span&gt;    { }&lt;/pre&gt;

  &lt;pre&gt;&lt;span class="lnum"&gt;  11:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;and remember to activate the &amp;quot;UseNamespaceDocSummaries&amp;quot; setting! Hopefully you will soon see a full-fledged example project soon when we release Common.Logging 2.0 in the next couple of days.&lt;/p&gt;

&lt;h5&gt;Cool - I want it for my own projects!&lt;/h5&gt;

&lt;p&gt;First of all, all these features just work for the MSDN documenter yet. Since unfortunately there is no nightly build set up yet (any volunteers out there?), you need to grab the code from &lt;a href="https://ndoc3.svn.sourceforge.net/svnroot/ndoc3/trunk" target="_blank"&gt;SVN&lt;/a&gt; and simply execute the nant script in the root folder of the trunk - see the &lt;a href="https://ndoc3.svn.sourceforge.net/svnroot/ndoc3/trunk/README.txt" target="_blank"&gt;readme.txt&lt;/a&gt; file for more info. Note, that you need a recent nightly build of NAnt, that supports .NET 3.5. Alternatively you can open the solution file and build the solution using VS2008.&lt;/p&gt;

&lt;h5&gt;... and keep the feedback coming&lt;/h5&gt;

&lt;p&gt;For any suggestions, feature request and bug reports please &lt;a href="http://apps.sourceforge.net/mediawiki/ndoc3/index.php?title=Contribute" target="_blank"&gt;use the sourceforge tracker or subscribe to one of our mailing lists&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully we will again see more projects in the .NET world being well documented.&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-5087568541917733970?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/5087568541917733970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=5087568541917733970' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/5087568541917733970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/5087568541917733970'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/03/ndoc-is-dead-long-live-ndoc3.html' title='NDoc is dead - long live NDoc3'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_NxkvYPY_Msg/SdI-NQ1yb9I/AAAAAAAAAB8/l-JFG2QR-BQ/s72-c/image_thumb%5B12%5D.png?imgmax=800' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-1733410365016487063</id><published>2009-03-29T13:38:00.001+02:00</published><updated>2009-03-29T13:58:33.557+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fun'/><title type='text'>just for fun</title><content type='html'>&lt;p&gt;A sun studio seen yesterday. I guess funny for geeks only&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh6.ggpht.com/_NxkvYPY_Msg/Sc9doUoxsxI/AAAAAAAAABw/v50BR5dwpAY/s1600-h/image%5B4%5D.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="92" alt="image" src="http://lh5.ggpht.com/_NxkvYPY_Msg/Sc9do3GShcI/AAAAAAAAAB0/ut34Z8M2DcY/image_thumb%5B2%5D.png?imgmax=800" width="363" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-1733410365016487063?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/1733410365016487063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=1733410365016487063' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1733410365016487063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/1733410365016487063'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/03/just-for-fun.html' title='just for fun'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_NxkvYPY_Msg/Sc9do3GShcI/AAAAAAAAAB0/ut34Z8M2DcY/s72-c/image_thumb%5B2%5D.png?imgmax=800' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2486313360029846926.post-4975961444491356509</id><published>2009-01-27T03:13:00.010+01:00</published><updated>2009-03-29T14:00:08.900+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><title type='text'>Thoughts on System.Diagnostics Trace vs. Common.Logging</title><content type='html'>&lt;p&gt;While working on the final bits for &lt;a href="http://netcommon.sourceforge.net/" target="_blank"&gt;Common.Logging 2.0&lt;/a&gt; I just looked a bit closer into NET’s trace model and tried to compare it to Common.Logging. I must admit that, being a long-time user of first log4net and then Common.Logging, I never much cared about &amp;lt;system.diagnostics&amp;gt;. Revisiting assumptions from time to time is a good habit, thus I dived into .NET tracing. Here’s what I found…&lt;/p&gt;  &lt;h5&gt;Configure and use &amp;lt;system.diagnostics&amp;gt;&lt;/h5&gt;  &lt;p&gt;The .NET trace system basically works by using TraceSources (=&amp;quot;Logger&amp;quot; in log4net) to write events to a list of TraceListeners (=&amp;quot;Appenders&amp;quot;) that decide whether a message to log by consulting a list of TraceFilters. This could be useful, alas there is no &amp;quot;batch&amp;quot; configuration possible, means you need to configure this chain for each TraceSource. Here's a minimum example what one needs to do:&lt;/p&gt;  &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.diagnostics&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sharedListeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;myListener&amp;quot;&lt;/span&gt;
             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MyTestTraceListener, MyAssembly&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;sharedListeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;source&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mySource&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;switchValue&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;All&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;listeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;myListener&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;listeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;source&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;sources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.diagnostics&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;    &lt;/pre&gt;

&lt;p&gt;Your code will then look like this:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;class&lt;/span&gt; MyClass
{
    &lt;span class="kwrd"&gt;readonly&lt;/span&gt; TraceSource trace = &lt;span class="kwrd"&gt;new&lt;/span&gt; TraceSource(&lt;span class="str"&gt;&amp;quot;mySource&amp;quot;&lt;/span&gt;);
    &lt;span class="kwrd"&gt;void&lt;/span&gt; Foo(&lt;span class="kwrd"&gt;object&lt;/span&gt; someArg)
    {
        &lt;span class="kwrd"&gt;try&lt;/span&gt;
        {
            Bar(someArg);
        }
        &lt;span class="kwrd"&gt;catch&lt;/span&gt; (Exception ex)
        {
            trace.TraceEvent(TraceEventType.Information, -1,
            &lt;span class="str"&gt;&amp;quot;error arg={0}:{1}&amp;quot;&lt;/span&gt;, someArg, ex);
        }
    }

    &lt;span class="kwrd"&gt;void&lt;/span&gt; Bar(&lt;span class="kwrd"&gt;object&lt;/span&gt; someArg) { &lt;span class="rem"&gt;/* do something */&lt;/span&gt;}
}&lt;/pre&gt;

&lt;p&gt;A nice tutorial on tracing is given in this &lt;a href="http://weblogs.asp.net/ralfw/archive/2007/10/31/code-instrumentation-with-tracesource-my-personal-vade-mecum.aspx"&gt;blog&lt;/a&gt;, some criticism is found &lt;a href="http://www.grimes.demon.co.uk/workshops/InstrWSSix.htm"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h5&gt;Performance Considerations&lt;/h5&gt;

&lt;p&gt;Of course you don’t want to pay much performance costs for your logging infrastructure. Fortunately tracing doesn’t cost you too much. I wrote some tests in Common.Logging to compare both and found Common.Logging twice as fast as Trace. Note, that we are talking about 2s vs. 4s for passing 100.000.000 log entries through the chain. I do not think that this is an issue for anyone except for applications generating an insane number of log entries.&lt;/p&gt;

&lt;p&gt;Things get interesting when evaluating a log message becomes expensive. Take for example the line from the example above:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;  trace.TraceEvent(TraceEventType.Information, -1,&lt;br /&gt;                           &lt;span class="str"&gt;&amp;quot;error arg={0}:{1}&amp;quot;&lt;/span&gt;, someArg, ex); &lt;/pre&gt;

&lt;p&gt;Somewhere within the tracing framework, the passed string and arguments must be evaluated and string.Format() gets called. But you do not want this to happen unless that message *really* gets logged – string.Format() calls both, someArg.ToString() and ex.ToString(), which might be very expensive to calculate!&lt;/p&gt;

&lt;p&gt;To be safe, you need to wrap all your calls by &lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; ( trace.Switch.ShouldTrace(TraceEventType.Information) )&lt;br /&gt;{&lt;br /&gt; trace.TraceEvent(TraceEventType.Information, -1,&lt;br /&gt;              &lt;span class="str"&gt;&amp;quot;error arg={0}:{1}&amp;quot;&lt;/span&gt;, someArg, ex);&lt;br /&gt;} &lt;/pre&gt;

&lt;p&gt;Unfortunately this doesn’t help in all cases. Most often you want all messages from all (or at least most) modules but only the informational ones (not the verbose). You can configure this using a filter:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;system.diagnostics&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sharedListeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;myListener&amp;quot;&lt;/span&gt;
             &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;MyTestTraceListener, MyAssembly&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;filter&lt;/span&gt; &lt;span class="attr"&gt;type&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System.Diagnostics.EventTypeFilter&amp;quot;&lt;/span&gt;
                    &lt;span class="attr"&gt;initializeData&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Information&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;sharedListeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;source&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mySource&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;switchValue&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;All&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;listeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;myListener&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;listeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;source&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;sources&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;system.diagnostics&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Using the configuration above, all messages will be passed into “myListener”, who’s filter will drop all messages above the information level. Unfortunately there is another issue: The framework automatically adds a DefaultTraceListener to all configured &amp;lt;source&amp;gt;s that will happily log all messages. To avoid this you need to write&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;source&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;mySource&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;switchValue&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;All&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;listeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="rem"&gt;&amp;lt;!-- prevent DefaultTraceListener from being added --&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;clear&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;add&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;myListener&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;listeners&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;source&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;I wrote some &lt;a href="https://netcommon.svn.sourceforge.net/svnroot/netcommon/projects/logging/trunk/modules/Common.Logging/test/Common/Common.Logging.Tests/PerformanceTests.cs" target="_blank"&gt;performance tests&lt;/a&gt; simulating the case where we only want to log Warnings. Messages are emitted at “Info” level, but the configuration should restrict messages to “Warning”s. On my box this resulted in &lt;/p&gt;

&lt;pre class="csharpcode"&gt;Time:00:00:01.9640000 - log.InfoFormat + NoOpLogger
Time:00:00:04.8410000 - traceSource.TraceEvent + unconfigured TraceSource
Time:00:00:03.6140000 - log.InfoFormat
Time:00:00:12.7380000 - traceSource.TraceEvent&lt;/pre&gt;

&lt;p&gt;As you can see, using tracing gets significant slower using the configuration above. Frankly I could not figure out what causes this. Things become unacceptable as soon as you forget to remove the DefaultTraceLogger:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;Time:00:00:00.6670000 - log.InfoFormat + NoOpLogger 
Time:00:00:02.2950000 - traceSource.TraceEvent + unconfigured TraceSource 
Time:00:00:02.2250000 - log.InfoFormat 
&lt;span style="color: rgb(255,0,0)"&gt;Time:01:00:23.8650000 - traceSource.TraceEvent &amp;lt;= not kidding here!&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;For this reason, Common.Logging introduced a new signature for logging leveraging the power of lambda expressions:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;  log.Info( m=&amp;gt;m(&lt;span class="str"&gt;&amp;quot;some logger info {0}&amp;quot;&lt;/span&gt;, (&lt;span class="kwrd"&gt;object&lt;/span&gt;)myObj) )&lt;/pre&gt;
Using this syntax you will always be on the safe side. Common.Logging will take care, that the message will only be evaluated in case it really gets logged. 

&lt;h5&gt;Conclusion&lt;/h5&gt;

&lt;p&gt;What bothers me most is the pain of configuring &amp;amp; using the trace framework. Here are the major pain points I found with the built-in tracing framework:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;It is possible to share listeners, but you need to configure the list of listeners for each TraceSource. &lt;/li&gt;

  &lt;li&gt;It is impossible to configure a default listener to be used by all TraceSources &lt;/li&gt;

  &lt;li&gt;There is no logging of exception objects possible &lt;/li&gt;

  &lt;li&gt;One can instruct a TraceListener to append the current callstack to the message, but this will include the System.Diagnostics stack(!) &lt;/li&gt;

  &lt;li&gt;No easy way for &amp;quot;batch&amp;quot; configuring log levels for multiple sources (like in log4net logger hierarchies), each source must be explicitly configured with level+listener &lt;/li&gt;

  &lt;li&gt;As soon as one configures the listeners for a TraceSource, a DefaultTraceListener will also be added to the list, causing each message to be logged to OutputDebugString as well (add a &amp;lt;clear/&amp;gt; element to the sample above. &lt;/li&gt;

  &lt;li&gt;It is incredible verbose to use, both tracing and configuring &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If one insists on avoiding a dependency on Common.Logging or log4net, go with tracing – you’ve been warned.&lt;/p&gt;

&lt;p&gt;For all others I recommend grabbing &lt;a href="http://netcommon.sourceforge.net/" target="_blank"&gt;Common.Logging&lt;/a&gt;. It allows you to defer the decision of which logging framework to use until the moment you deploy your application. &lt;a href="http://netcommon.sourceforge.net/doc-latest/reference/html/ch01.html#logging-declarative-config" target="_blank"&gt;Simply plug in&lt;/a&gt; any other logging system you might want to use. If you need to turn off logging at all, configure &lt;a href="http://netcommon.sourceforge.net/doc-latest/reference/html/ch01.html#logging-noop" target="_blank"&gt;NoOpLoggerFactoryAdapter&lt;/a&gt; and minimize the costs of your log statements to almost zero - guaranteed! &lt;/p&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2486313360029846926-4975961444491356509?l=eeichinger.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://eeichinger.blogspot.com/feeds/4975961444491356509/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2486313360029846926&amp;postID=4975961444491356509' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/4975961444491356509'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2486313360029846926/posts/default/4975961444491356509'/><link rel='alternate' type='text/html' href='http://eeichinger.blogspot.com/2009/01/thoughts-on-systemdiagnostics-trace-vs.html' title='Thoughts on System.Diagnostics Trace vs. Common.Logging'/><author><name>Erich Eichinger</name><uri>http://www.blogger.com/profile/01777569034256321263</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://3.bp.blogspot.com/_NxkvYPY_Msg/SsM5YFMBWkI/AAAAAAAAADM/d7jgTYdsoNQ/S220/portrait_10322_1085072060886_1648938068_207620_7313018_a.jpg'/></author><thr:total>13</thr:total></entry></feed>
