Sunday, October 17, 2010

C# inverse of control

I've used my simple inverse of control class, but I needed a singleton for a configuration class.
Here is a new version, just a little bit more complex, but capable of handling singletons.

    public enum RegisterScope
    {
        Instance = 1,
        Singleton
    }
    public static class Container
    {
        private static IDictionary<Type, Type> _types = null;
        private static IDictionary<Type, object> _singletonInstances = new Dictionary<Type, object>();
        public static void AutoRegister()
        {
            if (_types == null)
            {
                _types = new Dictionary<Type, Type>();
                Assembly assembly = Assembly.GetExecutingAssembly();
                foreach (Type contractType in assembly.GetTypes())
                {
                    if (contractType.IsInterface)
                    {
                        Type implementationType = assembly.GetType(contractType.FullName.Replace("Interfaces.I", "Implementation."));
                        if (implementationType != null)
                            _types[contractType] = implementationType;
                    }
                }
            }
        }
        public static void Register<TContract, TImplementation>(RegisterScope registerScope)
        {
            Register<TContract, TImplementation>();
            if (registerScope == RegisterScope.Singleton)
                _singletonInstances.Add(typeof(TImplementation), null);
        }
        public static void Register<TContract, TImplementation>()
        {
            if (_types == null) AutoRegister();
            _types[typeof(TContract)] = typeof(TImplementation);
        }
        public static T Resolve<T>(RegisterScope registerScope)
        {
            return (T)Resolve(typeof(T), registerScope);
        }
        public static T Resolve<T>()
        {
            return (T)Resolve(typeof(T));
        }
        public static object Resolve(Type contract, RegisterScope registerScope)
        {
            if (_types == null) AutoRegister();
            if (registerScope == RegisterScope.Singleton)
            {
                Type implementation = _types[contract];
                if (!_singletonInstances.Keys.Contains(implementation))
                    _singletonInstances.Add(implementation, null);
            }
            return Resolve(contract);
        }
        public static object Resolve(Type contract)
        {
            if (_types == null) AutoRegister();
            Type implementation = _types[contract];
            if (!_singletonInstances.Keys.Contains(implementation))
                return Instanciate(implementation);
            else
            {
                if (_singletonInstances[implementation] == null)
                    _singletonInstances[implementation] = Instanciate(implementation);
                return _singletonInstances[implementation];
            }
        }
        private static object Instanciate(Type type)
        {
            ConstructorInfo constructor = type.GetConstructors()[0];
            ParameterInfo[] constructorParameters = constructor.GetParameters();
            return constructorParameters.Length == 0
                ? Activator.CreateInstance(type)
                : constructor.Invoke(constructorParameters.Select(parameterInfo => Resolve(parameterInfo.ParameterType)).ToArray());
        }
    }

Same as the simple container, the only restriction is that you have to use a naming convention for default implementations.

  • Interface example: YourNamespace.Interfaces.ISomeObject
  • Implementation example: YourNamespace.Implementation.SomeObject

You may use the auto registration and then override some interface registration (for mockups, Web or services for instance).

The code to use afterwards... again, a single line.
ISomeObject someObject = Container.Resolve<ISomeObject>(RegisterScope.Singleton);
Or if you need a new instance, use the Resolve method without parameters.

ISomeObject someObject = Container.Resolve<ISomeObject>();

You may use this code in your project if it fits your needs. Fell free to add a comment if you have questions.

Simple C# inverse of control

I try to avoid third party tools whenever possible. Almost every time I used one, I had to deal with several updates, filtering functionality too complex for my needs, lack of support or maintenance over the time an so on.
I'm using a lot of Domain Driven Design lately and I really like it. Plus, I use a technique called inverse of control which allows dealing only with interfaces on Web applications. This is a great deal, because I'm able to use the implementation I need (Web, service or even mock-ups during development), plus it makes testing much easier.
There are a lot of third party components implementing inverse of control: Castle Windsor, StructureMap, Spring.NET, Autofac, and so on.
But since I don't like to use third party tools, I'm more inclined to use a simple version good enough for my project needs. There are several code examples on the net, like IoC container in 15 lines or IocContainer in 15 minutes.
Here is a simple version I've build, which allows the Interfaces to be automatically registered, son I don't have to write additional code or to use a configuration file. Everything is much simpler, so this is my thing.

    public static class SimpleContainer
    {
        private static IDictionary<Type, Type> _types = null;
        public static void AutoRegister()
        {
            if (_types == null)
            {
                _types = new Dictionary<Type, Type>();
                Assembly assembly = Assembly.GetExecutingAssembly();
                foreach (Type contractType in assembly.GetTypes())
                {
                    if (contractType.IsInterface)
                    {
                        Type implementationType = assembly.GetType(contractType.FullName.Replace("Interfaces.I", "Implementation."));
                        if (implementationType != null)
                            _types[contractType] = implementationType;
                    }
                }
            }
        }
        public static void Register<TContract, TImplementation>()
        {
            if (_types == null) AutoRegister();
            _types[typeof(TContract)] = typeof(TImplementation);
        }
        public static T Resolve<T>()
        {
            return (T)Resolve(typeof(T));
        }
        public static object Resolve(Type contract)
        {
            if (_types == null) AutoRegister();
            Type implementation = _types[contract];
            ConstructorInfo constructor = implementation.GetConstructors()[0];
            ParameterInfo[] constructorParameters = constructor.GetParameters();
            return constructorParameters.Length == 0
                ? Activator.CreateInstance(implementation)
                : constructor.Invoke(constructorParameters.Select(parameterInfo => Resolve(parameterInfo.ParameterType)).ToArray());
        }

Prety simple. The only restriction is that you have to use a naming convention for default implementations.
  • Interface example: YourNamespace.Interfaces.ISomeObject
  • Implementation example: YourNamespace.Implementation.SomeObject
Of course, you may use the auto registration and then override some interface registration (for mockups for instance).

The code to use after is really simple, a single line. No config, no extra registration lines, no nothing. Just use the resolve method and you're done.
ISomeObject someObject = Container.Resolve<ISomeObject>();


Feel free to use this piece of code if it fits your needs.

Monday, October 11, 2010

HTML5 - the new kid on the block

We all like HTML5, CSS3 and the new Web standards, but we may think that we are not ready to use them. Well, it's not true. The world goes mobile, 95% of mobile browsers are Webkit based so HTML5 is well supported on mobile space - I'm talking about smartphones, of course; everybody should and will have a smartphone soon enough. Plus, there are smart frameworks on the net allowing to develop HTML5+CSS3+JavaScript applications that can be published to native apps for iPhone, Adroid, Blackberry and other. Take a look at http://www.phonegap.com/ for instance.
For more information, please check my HTML5 presentation on Slideshare (http://www.slideshare.net/MarianBorca/html5-the-new-kid-on-the-block).
This is the future of the Web, starting now!