This project is read-only.

Mojo Dependency Injection Framework

Mojo is a new kind of DI framework for .NET that combines AOP with old school factory methods in order to deliver 100% typesafe dependency injection.

Links: (under construction)
  • FAQ
  • Templates
  • Factory methods
  • Configuration methods
  • Threading

Motivation

I love the concept of DI, but I dislike how other frameworks deal with it.
This is ofcourse only my personal opinion but below is a list of things that I find problematic in other frameworks:

XML Configs
Most other frameworks use XML as some sort of DSL to describe how objects should be created and relate to each other.
Those configs are always hard to create or maintain, simple things like attaching events or using generics become a pain or might simply be impossible to do.
Describing complex object activation in a way that a human can read and understand it is not one of the strong sides of XML.

Named objects (using strings)
Almost all DI frameworks support named objects.
Being able to reference to a specific object is great, but there are other ways to do so w/o using string names.
string names does not come with intellisense and nor is it supported by the refactoring features in VS.NET.

So how does Mojo do it?

Configurations
Mojo uses "templates" for configuration, a template is simply an interface or class that describe what objects you are going to use in your application.
When using a Mojo container you tell it what template you want to use as a contract and the framework can then load the implementation for that contract into the container.

Eg:

This will tell the framework that you want a container for the HelloWorldTemplate and then load the implementation for this template for you.
var context = Context.Configure<HelloWorldTemplate>(); 


Or, you can explicitly tell it what implementation to use (This is useful when dealing with unit tests, as you can provide testing templates)
var context = Context.Configure<IMyContract, MyImplementation>(); 


Creating Configurations

Templates are normal classes so the only thing you have to do is to add a new class and inherit from "Mojo.Template":
public class HelloWorldTemplate : Template
{

    [FactoryMethod(InstanceMode.PerCall)]
    public virtual Foo MyFoo()
    {
         //this will execute each time you ask for MyFoo
         Foo foo = CreateObject<Foo>();
         foo.SomeProp = 123;
         foo.Bar = MyBar()
         return foo;
    }

    [FactoryMethod(InstanceMode.PerContext)]
    public virtual Bar Mybar()
    {
         //this will only execute once per container
         Bar bar = CreateObject<Bar>();
         return bar;
    }     
}


This template contains the defenition for two objects: "MyFoo" and "MyBar".
These two methods looks just like normal factory methods, and that's exactly what they are.

So what does Mojo add to the table?! Did you just wrap a container around a normal factory class?!
No..
Mojo adds the container and activation features of a DI framework, such as object caching, type substitution and much more.

The attributes on the methods tells the framework that those are factory methods and the framework will add code behind the scenes in order to handle object activation rules.
Mojo Containers use NAspect AOP engine in order to apply these features.

Eg. The first method "MyFoo" is marked as PerCall, this means that there will be a new "Foo" object created every time you ask the container for MyFoo.
The second method is marked with PerContainer, this means that "MyBar" will only be created once per container.
So Mojo is enabling normal factory methods to call each other in the context of a container and the container will decide if an object needs to be created or not.

There are four types of instance modes for objects in Mojo:
  • Per Call
  • Per Graph
  • Per Container
  • Per Thread

Custom modes are under construction, this will allow you to cache objects in web sessions etc.

Object resolution
Since Mojo uses typed templates, you can resolve objects like this:
   Foo myFoo = context.Template.MyFoo();

This comes with a number of benefits:

You get intellisense so you can see exactly what objects that your container can give you.
Other frameworks which use named objects can never tell you what objects the container can return.

You do not need to specify the type of the object that you want to use.
Other frameworks needs a generic type argument or you will have to cast manually.

You can mark objects that the developers are supposed to use as public and other helper/infrastructure objects as protected, thus hiding them from the consumer.
Other frameworks does not have visibility features on their object configurations.

It is 100% type safe and you can refactor your templates just like any other code.

You can even add XML comments to describe what your factory methods do, so the user of the container will get extra intellisense info.

And best of all, you do not have to learn some awkward XML DSL, you can use any .NET language for your templates.

Templates and Inheritance
Since the templates are classes, you can easily inherit them and override factory methods if you want.
Thus making it possible to reuse templates for different scenarios, eg for different customers or for your unit tests.

Last edited May 2, 2008 at 4:30 PM by Roggan, version 58