I'm building an application which will monitor other applications (memory using, start them if they crash, etc). I'm trying to stop re-inventing the wheel (ohhh, it’s fun to do everything yourself) and start using other components. This time, I needed an IoC container and autofac seemed like a good match for me.
To simplify IoC registration, I created an attribute which I use on all my components. In this way, I don't have to remember to register each component, it’s done with the help of the attribute.
Using the attribute without constructor parameters will register the component with all interfaces.
[Component]
class MyComponent : IConsumer<MonitorEvent>, ISomeService
{
}
While using the constructor will only register one interface.
[Component(typeof(ISomeService)]
class MyComponent : IConsumer<MonitorEvent>, ISomeService
{
}
The autofac registration looks like this:
internal class Program
{
public static IContainer Components { get; private set; }
private static void Main(string[] args)
{
var builder = new ContainerBuilder();
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
assemblies.Each(assembly => assembly.FindComponents((i, c) =>
builder.RegisterType(c).As(i).SingleInstance()));
Components = builder.Build();
}
}
Quite smooth, huh?
Extension methods making it possible:
public static class ComponentFinder
{
public static void Each<T>(this IEnumerable<T> enumerable, Action<T> action)
{
foreach (T item in enumerable)
action(item);
}
public static void FindComponents
(this Assembly assembly, Action<Type, Type> action)
{
Type componentAttribute = typeof (ComponentAttribute);
foreach (Type type in assembly.GetTypes())
{
object[] attributes = type.GetCustomAttributes(componentAttribute, false);
if (attributes.Length == 0)
{
type.GetInterfaces().Each(i => action(i, type));
continue;
}
foreach (object attribute in attributes)
{
Type interfaceType =
((ComponentAttribute) attribute).InterfaceType ?? type;
action(interfaceType, type);
}
}
}
}
Getting components is done by the resolve
method:
Program.Components.Resolve<IMyService>.SendMessage("Hello world");