spring-recoil


Fluent configuraton API for Spring.NET

Recoil: a fluent API for building object definitions for Spring.NET

Version 1.1.3 is released! Grab it here: 1.1.3 - It comes with initializer method support (many thanks to Graham Nash) and object configuration inheritance (many thanks to Maxim Klyuchnikov)

Contribution

Feedback and even contribution are both very much welcome, as they are the only way to make Recoil better. If you have ideas, objections or comments, feel free to stop by at the Discussion.

The source is kept in a Mercurial repository that you can easily retrieve. If you would like to have contrib rights, please let one of the project owners know.

Patches

If you found a bug or made a quick improvement, the easiest way to have it included in the next release is to send a patch to the project owners or contributors. Alternatively just drop a message at the main discussion board.

Getting started

Installation

There is no real installation neccessary, apart from downloading the binaries and adding a reference to your project. Setting up Spring.NET itself is beyond the scope of this tutorial, but you can find all the information you need here: http://www.springframework.net/documentation.html

NOTE: I'll add a short guide to the two most common ways of setting up Spring.NET IoC and basically get Recoil working from a blank project.

Configuration

Using Recoil is extremely simple. It works on a similar principle as Fluent NHibernate, in that you set up your object definitions in a subclass. In our case, the "marker" base is WiringContainer. The actual definitions need to be set up in a single abstract method that your subclass needs to implement:

public class MyWiringContainer : WiringContainer { public override void SetupContainer() { Define(() => new Test {Moof = new List<Foo> {new Foo(), new Foo()}}); Define(() => BarFactory.Create()) .As<IBar>() .Set(b => b.TestProperty).To(() => "TestValue"); Define<Test>().As("AnotherTest").AsSingleton(); } }

After you are happy with your creation, on the seventh day, you should rest. Having regained your stamina, you can now attempt to actually add your objects to Spring.NET; this can be accomplished in two ways:

Configure XmlApplicationContext

When using the built in facilities for instantiating a context based on the setting in the application configuration file.

In this case, simply add objects of type ObjectDefinitionRegistryConfigurer to your xml context definitions. These will be automatically recognized by spring. The constructor argument to ObjectDefinitionRegistryConfigurer is a list of your wiring containers:

<object type="Strongshell.Recoil.Core.Integration.ObjectDefinitionRegistryConfigurer, Strongshell.Recoil.Core"> <constructor-arg name="wiringContainerTypeNames"> <list element-type="System.String"> <value>Strongshell.Recoil.Sample.MyWiringContainer, Strongshell.Recoil.Sample</value> </list> </constructor-arg> </object>

Configure Manually Instantiated contexts

Recoil uses extension methods to make any context that implements IObjectDefinitionRegistry configurable:

var myContext = new GenericApplicationContext(); myContext.Configure().With<MyWiringContainer>() .With<AnotherWiringContainer>(); myContext.Refresh();

Et Voila! Your context now contains your fluently configure object definitions.

Defining objects

This is again, quite simple. By following the fluent interface you always get the possibilities that make sense in the current context and you can discover all methods by simple exploration in 5 minutes.

All the object definition properties (autowiring, singleton/prototype lifetime...) are accessible through the fluent interface right out of the box.

To get you started, here are a few examples:

Defining an object with a custom constructor and member initializers

Define(() => new Bar("StringArgument", 5) { TestProperty = "Value" });

Please note that you don't even need to specify the object type, since the compiler can infer it from the return value of the constructor. Recoil even generates a well behaved object name by default which is the full type name (NameSpace+Class Name).

Injecting dependencies using the Wire() methods

Define(() => new Bar(Wire<IFoo>()));

The Wire() methods can be used anywhere in the object definition, and Recoil will wire that dependency to a reference instead of a value.

Embedding objects

Define(() => new Test { Moof = new List<Foo> { new Foo(), new Foo { Bar = Wire<IBar>() } } });

This is a nicely nested graph! However, recoil will create proper embedded object definitions and will even wire up that Bar property correctly to a reference. Embedded objects can be treated as anonymous, but under the hood they just get a unique name generated to make sure there are no clashes.

Recoil can handle all objects that implement IList and IDictionary and converts them to Spring.NET managed collections.

Using factory method instantiation

Define(() => BarFactory.Create()) .As<IBar>() .Set(b => b.TestProperty).To(() => "TestValue");

Recoil will recognize the above pattern as a static factory method instantiation (provided that Create() is a static method of BarFactory). Since member initializers can't be used in this case, there is API provided for setting up properties like above.

Instance factory methods work very similarly:

Define(() => Wire<IBarFactory>.Create());

As you see, you can use the Wire() method to get a kind of "placeholder" of the factory class, and call the factory method. The method won't be called by Recoil of course, it is only a pattern that it can recognize to correctly set up your objects.

Using factory method instantiation on embedded objects

Define<Foo>() .Set(f => f.Bar).To(() => BarFactory.Create());

The pattern is really becoming obvious here :), the instance of Bar that will be injected into the property of Foo will be created by a static factory. Under the hood, an anonymous object definition will be created (of type Bar), with static factory method instantiation.

Project Information

Labels:
IoC Fluent Spring.NET .NET Windows