This project is read-only.

Automatic inject properties

Mar 22, 2014 at 11:02 AM
Hi,

I am a newbie of Simple Injector and I need to port Ninject to Simple Injector. In Ninject, I can automatic inject concrete class to interface by Name Convention (Ex: User class inject to IUser interface without explicit register). So how can I do it with Simple Injector ? I don't need to explicit register with many interfaces and concrete classes.

Thanks.
Mar 22, 2014 at 11:20 AM
I'm not sure I understand what behavior you want. Can you post a link to documentation of the feature of Ninject you are referring to?
Mar 22, 2014 at 1:17 PM
Edited Mar 22, 2014 at 1:29 PM
Yes, you can see that feature at this link https://github.com/ninject/ninject.extensions.conventions . In my project, I have many interfaces and concrete classes and I don't explicit register in Simple Injector like that :

container.Register<IUser, User>();
container.Register<IPerson, Person>();
container.Register<IMyFile, MyFile>();
..etc..

I need to one line code for register all cases which the concrete class has the same name of interface with "I" before name.

Hope your help.
Mar 22, 2014 at 1:47 PM
There's nothing in Simple Injector that supplies you with this behavior out-of-the-box, but there are two ways to achieve this.

1. You can batch register those types up front by defining a LINQ query over the assemblies to search. For instance:
Assembly[] assembliesToLookIn = new[] { Assembly.GetExecutingAssembly() };

var registrations =
    from assembly in assembliesToLookIn
    from type in assembly.GetExportedTypes()
    where type.IsClass && !type.IsAbstract && !type.IsGenericTypeDefinition
    where type.GetInterfaces().Length == 1
    group type by type.GetInterfaces().First() into g
    where g.Count() == 1
    select new { Interface = g.Key, Implementation = g.First() };

foreach (var registration in registrations)
{
    container.Register(registration.Interface, registration.Implementation);
}
Simple Injector contains batch registration features, but solely for registering generic types. There's no batch registration API for non-generic types. Although many DI frameworks contain an advanced API for doing convention based registration, we found that doing this with custom LINQ queries is often easier to write, easier to understand, and even more flexible than using such an API.

2. You can use just-in-time registration using the ResolveUnregisteredType event of the container:
Assembly[] assembliesToLookIn = new[] { Assembly.GetExecutingAssembly() };

container.ResolveUnregisteredType += (s, e) =>
{
    if (e.UnregisteredServiceType.IsInterface)
    {
        var types = (
            from assembly in assembliesToLookIn
            from type in assembly.GetExportedTypes()
            where type.IsClass && !type.IsAbstract
            where e.UnregisteredServiceType.IsAssignableFrom(type)
            select type)
            .ToArray();

        if (types.Length == 1)
        {
            e.Register(Lifestyle.Transient.CreateRegistration(types[0], container));
        }
    }
};
Benefit of this approach is that the container will only go look for an implementation when the type is first resolved. Downside of this approach is that if those types are root types (types that are resolved directly from the container), the container will be unaware of their existence (until they are resolved for the first time), and this makes it much harder to verify the container's correctness, and disallows the container to diagnose those types.
Marked as answer by dot_NET_Junkie on 4/15/2014 at 1:48 AM
Mar 22, 2014 at 1:53 PM
Nice tip. Thank for your help. I will attempt this.