Sunday, August 29, 2010

Register Spring.Net objects with code

Anyone that has worked with Spring.Net is probably familiar with configuring the IOC container using an XML document. A typical example would be:

   3: <objects xmlns="" 
   4:          xmlns:v='' 
   5:          xmlns:aop="" 
   6:          xmlns:db="" 
   1: <?xml version="1.0" encoding="utf-8"?>
   9:   <object id="ConsoleWriter" type="SimpleCalculatorWithComplexTree.Writers.ConsoleWriter" singleton="false" >
  10:     <constructor-arg name="formatter" ref="HexFormatter" />
  11:   </object>
  13:   <object id="Calculator" type="SimpleCalculatorWithComplexTree.Calculator" singleton="false">
  14:     <constructor-arg name="writer" ref="ConsoleWriter" />
  15:   </object>
  17:   <object id="HexFormatter" type="SimpleCalculatorWithComplexTree.Formatters.HexFormatter" singleton="false" >
  19:   </object>
  21: </objects>

The last couple of years has seen an anti-XML movement begin to form. In the world of IOC containers, this has materialized as a movement away from XML configuration and more towards using code constructs and “convention over configuration.” I’m not against XML. After all, almost everything has a place.

I recently did a presentation on Spring.Net for a .NET user group. I wanted to introduce the IOC container without overwhelming people with XML. A quick search found an article about XMLless configuration of the container. This approach felt like it would be a distraction from my goal of getting to the container.

Luckily I stumbled into at article from early 2008 that discussed the configuration api. From this I was able to create this method that extends the GenericApplicationContext and allows for easy registration of a type in the container:

   1: Imports System.Runtime.CompilerServices
   2: Imports Spring.Context.Support
   3: Imports Spring.Objects.Factory.Support
   5: Public Module SpringExtension
   7:     <Extension()>
   8:     Public Sub RegisterType(Of T)(ByVal ctx As GenericApplicationContext, ByVal builderConfig As Action(Of ObjectDefinitionBuilder))
   9:         Dim objectDefinitionFactory As IObjectDefinitionFactory = New DefaultObjectDefinitionFactory()
  11:         Dim builder As ObjectDefinitionBuilder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, GetType(T))
  12:         builderConfig.Invoke(builder)
  14:         ctx.RegisterObjectDefinition(builder.ObjectDefinition.ObjectType.Name, builder.ObjectDefinition)
  16:     End Sub
  18: End Module

Here’s a quick example of its use:

   1: Dim ctx = New GenericApplicationContext()
   3: ctx.RegisterType(Of Calculator)(Sub(b As ObjectDefinitionBuilder) b _
   4:                               .SetAutowireMode(Spring.Objects.Factory.Config.AutoWiringMode.AutoDetect) _
   5:                               .SetSingleton(False))
   7: ctx.RegisterType(Of HexFormatter)(Sub(b As ObjectDefinitionBuilder) b _
   8:                       .SetAutowireMode(Spring.Objects.Factory.Config.AutoWiringMode.AutoDetect) _
   9:                       .SetSingleton(False))
  11: ctx.RegisterType(Of ConsoleWriter)(Sub(b As ObjectDefinitionBuilder) b _
  12:                       .SetAutowireMode(Spring.Objects.Factory.Config.AutoWiringMode.AutoDetect) _
  13:                       .SetSingleton(False))


  1. Do you care to elaborate "This approach felt like it would be a distraction from my goal of getting to the container"?

  2. Erich,

    >> Do you care to elaborate...

    Sure. I wanted something simple that I could use to put a couple of objects into the container. The extension method is three or four lines long and I was able to flip to the class, gloss over what it was doing, and continue describing what the container was and what it was capable of.

    I'm sure that the CodeConfig component is more feature complete, and I see that it has an assembly scan feature - which is something that was asked about at the presentation.