Saturday, July 12, 2008

Ninject revisited

In a previous post, I looked at Ninject, and based on a cursory look at the documentation, dismissed it as requiring me to decorate my component classes with attributes in order to use multi-parameter constructor injection. Thanks to a comment by ninject's author, Nate Kohari, I found that with a slight configuration change, we can duplicate the behavior of Unity.

The proof's in the pudding. Let's see if we can wire up the same components with both Unity and Ninject without having to make any changes to our component classes.

Here are some interfaces:

public interface IDataService
{
}

public interface ISecurityService
{
}

public interface ILogger
{
}


And here are some components that use them. The Business Logic requires all three, the Security service needs a DataService and Logger, and the DataService needs a Logger.



public class BusinessLogic
{
protected IDataService DataService { set; get; }
protected ILogger Logger { set; get; }
protected ISecurityService SecurityService { set; get; }

public BusinessLogic()
{
}

public BusinessLogic(ILogger logger, IDataService dataService, ISecurityService securityService)
:this()
{
this.Logger = logger;
this.DataService = dataService;
this.SecurityService = securityService;
}


public override string ToString()
{
return base.ToString() + '\n' +
Logger.ToString() + '\n' +
DataService.ToString() + '\n' +
SecurityService.ToString() + '\n'
;
}
}


public class DataService : IDataService
{
protected ILogger Logger { set; get; }

public DataService()
{
}

public DataService(ILogger logger)
:this()
{
this.Logger = logger;
}
}

public class SecurityService : ISecurityService
{

protected IDataService DataService { set; get; }
protected ILogger Logger { set; get; }

public SecurityService()
{
}

public SecurityService(ILogger logger, IDataService dataService)
: this()
{
this.Logger = logger;
this.DataService = dataService;
}
}

public class Logger : ILogger
{
}


If we don't want to use an auto-wring container, we need to know all the dependecies and create the Business object like so:



static BusinessLogic NormalWay()
{
var logger = new Logger();
var dataService = new DataService(logger);
var securityService = new SecurityService(logger, dataService);
var bizLogic = new BusinessLogic(logger, dataService, securityService);
return bizLogic;
}



How do we configure and create a BusinessLogic object with Unity? Like so:



static BusinessLogic UnityWay(UnityContainer container)
{
UnityContainer container = new UnityContainer();
container
.RegisterType<ILogger, Logger>()
.RegisterType<IDataService, DataService>()
.RegisterType<ISecurityService, SecurityService>()
;
var bizLogic = container.Resolve<BusinessLogic>();
return bizLogic;
}
}


Likewise, we can create a method to create a BusinessLogic object using Ninject, all auto-wired are ready to go. This however, requires a configuration class (MyModule):



static BusinessLogic NinjectWay()
{
var kernel = new StandardKernel(new MyModule(), new AutoWiringModule());
var bizLogic = kernel.Get<BusinessLogic>();
return bizLogic;

}
private class MyModule : StandardModule
{
public override void Load()
{
Bind<ILogger>().To<Logger>();
Bind<IDataService>().To<DataService>();
Bind<ISecurityService>().To<SecurityService>();
}
}



We can run the following to show that the objects get create and populate the services:



static void Main(string[] args)
{
BusinessLogic bz;

bz = NormalWay();
System.Console.WriteLine(bz);

bz = UnityWay();
System.Console.WriteLine(bz);

bz = NinjectWay();
System.Console.WriteLine(bz);

}

So the end result is that we can design our components and use constructor-injection. So long as we keep container-dependencies out of our business components, an app can be assembled using the container of your choice.

Thursday, July 3, 2008

Looking at Ninject

Not to be too Microsoft-centric, I decided to look at the DI container Ninject, which has recently been released by Nate Kohari. After all, if we write our components correctly (POCOs), then swapping out containers should be a trivial exercise.

I looked at the docs on Ninject's constructor injection and found the following:

You also have the option to leave off the [Inject] attribute completely. This can help if you don't have access to the source code of a class, but you still want to inject dependencies into it. Here's the logic Ninject follows to choose which constructor to call, if none have an [Inject] attribute:

  1. If the type only has a single constructor, Ninject will call it.
  2. If the type has more than one constructor, but has a default (parameterless) constructor available, Ninject will call it. (This also applies to types that have no explicit constructors defined.)

I think that's a deal-breaker. Adding Attributes to my classes is not an option, because I want to maintain container-independency. In order to work correctly with constructor-injection, I need the container to call the container with as many parameters as it can satisfy. I will often have a parameterless constructor in my component to supply default values for the object for legacy code which is not using a container.

I'll take another look at Ninject if the constructor-injection strategy changes. The site has really sweet icons, by the way. Here's a sample:

Fun with C# 3.0 (#3) - Lambda expressions

The addition of LINQ to C#/.NET has really improved the way that we can handle data in our applications. Here's an example.

Suppose we want to write a method to count the number of strings in a list which exceed a certain length. It's not to hard to do with C# 2.0; you iterate over the items, make the comparison, increment a counter and return it. But C# 3.0 makes it simple.

When the namespace System.Linq is included in your file, IEnumerable objects get a load of new extension methods. One of them is Where, which will return a sub-collection of items that match a filter. The filter is defined as a lambda expression that returns a bool. If the item causes the lambda expression to evaluate to true, then the item will be included in the sub-collection. Let's look at some code:

public int NumberLongerThan(List<string> list, int n)
{
var subList = list.Where(
(string str) => str.Length > n
);
return subList.Count();
}


Here we pass in a List<string> and a number. The subList will have the string items that are longer than n characters. Note that we don't have to define the type of subList; the compiler can infer it at compile-time.



Here is the code that uses the method.



List<string> list = new List<string>() { "abc", "def", "GH", "ijKL", "mnop", "QRSTUV", "Wxyz" };
Console.WriteLine(NumberLongerThan(list, 0));
Console.WriteLine(NumberLongerThan(list, 1));
Console.WriteLine(NumberLongerThan(list, 2));
Console.WriteLine(NumberLongerThan(list, 3));


This is the lambda expression:



(string str) => str.Length > n


It states that a string is passed in and returns a bool based on the test of the string Length. The Where() method takes an expression that expects a string and returns a bool. Since the compiler knows this, we can let it infer the type of the parameter and specify the expression like so:



str => str.Length > n


Also, note that if we have a named method that is of the correct delegate type (Func<T, bool>), we can pass it to Where(). Here, List<T> is List<string>, so the method must take a string parameter.



public bool TestString(string s) { return s.Length > 3; }


var filtered = list.Where(TestString);
//-- or --
Func<string, bool> f = TestString;
var list2 = list.Where(f);


The advantage of using the unnamed lambda expression is that we can reference the local variable n as a parameter in our test expression.



More info at Charlie Calvert's blog.