August 16, 2005

Custom Attributes for NanoContainer.NET

I recently rolled onto the Beach after working on the same project for the past 7+ months. The project successfully utilize PicoContainer.NET for configuring both the client and server.

A colleague of mine, Jay Fields, and I have been discussing the use of .NET Attributes with pico/nano. I have for a while felt that the .NET implementation of pico and nano have really just been straight ports of the Java code while not really taking advantage of the features C# offers. One particular useful addition are Attributes.

So the past few days we have worked on a spike to take advantage of Attributes in the NanoContainer.NET. Utilizing Attributes in the code will allow us to define how an object is added to the container and will free us from having to create a separate script for loading the container. Here is an overview of the work we have done:

Attribute:


RegisterWithContainerAttribute - This is a class level attribute used by concrete classes that need to be registered with the container. The properties of this class are:
  • object key: which represents the key the component should be registered against
  • ComponentAdapterType componentAdapterType: An enum that defines the type of component adapter (choices consist of Caching, NonCaching and Custom). Caching is the default.
  • DependencyInjectionType dependencyInjectionType: An enum that defines the DI construct to follow (Constructor or Setter are the choices) as expected Constructor is the default type.
  • Type componentAdapter: represents the concrete Type to use as the component adapter. This allows a concrete class to define a custom component adapter to use for itself.


Examples of use:

// constructor based with caching...
[RegisterWithContainer]
public class Foo : IFoo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}

// setter based with caching
[RegisterWithContainer(DependencyInjection=DependencyInjectionType.Setter)]
public class Foo : IFoo
{
private IBar bar;

public IBar Bar
{
set {this.bar = value; }
}
}

// constructor based with non-caching...
[RegisterWithContainer(ComponentAdapterType.NonCaching)]
public class Foo : IFoo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}

// setter based with non-caching...
[RegisterWithContainer(ComponentAdapterType.NonCaching,
DependencyInjection=DependencyInjectionType.Setter)]
public class Foo : IFoo
{
private IBar bar;

public IBar Bar
{
set {this.bar = value; }
}
}

// utilize a custom component adapter (caching and injection type are ignored for custom)
[RegisterWithContainer(ComponentAdapterType.Custom,
ComponentAdapter=typeof(CustomComponentAdapter))]
public class Foo : IFoo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}

// example of the custom component adapter...
public class CustomComponentAdapter: CachingComponentAdapter
{
public CustomComponentAdapter(Type type)
: base(new ConstructorInjectionComponentAdapter(type))
{
}
}

Now the CustomComponentAdapter doesn't really serve a purpose in this example, but I think it gets the point across. I think this addition to NanoContainer.NET is extremely useful and takes advantage of the language features. I think it also opens up the idea of utilizing similar functionality for Java 5.0 Annotations. Consistency between the two would be great.

No comments: