DISQUS

DISQUS Hello! Andrey Shchekin's Blog is using DISQUS, a powerful comment system, to manage its comments. Learn more.

Community Page

Jump to original thread »
Author

Comparing .NET DI (IoC) Frameworks, Part 2

Started by Andrey Shchekin · 9 months ago

Note to RSS users: There are embedded spreadsheets in this posts that Google Reader silently hides. I prefer RSS myself, but for this post Zoho features are very useful and, unfortunately, I see no way to make it usable in Google Reader. Sorry about that.

I have finished the previous po ... Continue reading »

37 comments

  • Nice comparison! I didn't know that there where so many IoC frameworks :)

    Do you know if all containers support registering services/components at any given time?
    I know Castle can do that, i'm abusing it a bit in my current project.
  • Definitely not all, I think I'll add a test for that at some point.
  • Hi Andrey,

    If you take a look at the updated version of your test project, you'll notice that LinFu passes every test in both "MustHave" and "ShouldHave" categories--all from an assembly that is only about 94KB in size! :)

    If you can, please update your charts accordingly. Thanks!
  • Cool, great work!

    I think I can't update in-post chart, since it'll require me to update post text as well, and that would mean I have to consider and mention all other framework updates.
    I am looking for a way to keep an up-to-date version of charts at the net-ioc-frameworks page of Google Code, I hope to do it soon enough.
  • Fantastic review! Thanks for writing it. By the way, the problem with the ExtensionAttribute has been fixed in the latest trunk build of Ninject, which will be released as 1.5 soon.
  • Thank you. I think at some point I will make a new version of spreadsheet and update it as new framework versions come out.
  • Lol, just yesterday I posted something similar in spirit, but yours is a lot more thought out. It can be found here (http://realfiction.net/?q=node/166), but I'll link back to this anyway, since this is decent.
  • Thanks, I really like your review because it captures same main points (arrays for StructureMap, versioning for Castle) while being much shorter and easy to read. Thanks for the links as well.
  • Really like the overview. Don't know what I would choose since I don't seem to run into tasks that require this at the moment.
  • BTW, he new version of StructureMap (3.5) now uses RhinoMocks, not NMock
  • Thanks, I'll probably post an updated version of spreadsheet at some point.
  • Spring.NET fixed the List injection. It was also available through XML anyway.

    Thanks for the review.
  • Castle does support list injection - via configuration, http://www.castleproject.org/container/gettings.... I assume you are wanting it to be more generic, in that Castle would just automatically inject all the instances if IService. You may want to see if this could be bent to satisfy your needs.
  • I know about it, but I have no xml configuration in my project, so it does not really help me.
    I have made a custom Castle resolver, however it does not handle complex scenarios like circular reference tracking.
  • @Andrey,

    You can use the Container in StructureMap independently of the static ObjectFactory.

    IContainer container = new Container(r => {
    r.ForRequestedType<Foo>().TheDefaultIsConcreteType<Bar>();

    // and so on
    });

    I'm still not sold on the hierarchical container idea. In StructureMap, I use the "Profile" concept for the same purpose as a hierarchical container in Windsor.
  • That's great! I feel stupid for overlooking this solution, since it solves most of my concerns with StructureMap.

    As for hierarchical containers, I do like the disposable lightweight container idea of Autofac.
    Also I had a use case for explicitly hierarchical container with Castle, but that was not the only solution in that case.

    If I understand your profile idea correctly, it is an ability to switch between registrations sets.
    I would prefer an explicit using() {} block to a property in this case, since I always like to see context boundaries.
    Also instances are more easier from threading POV.
  • I have just fixed all relevant parts of the post.
  • Another great summary. Unity will have list injection (well, array injection specifically) in version 1.2. We're releasing the preview drop of this feature early next week.
  • Great work!

    Btw, do you realize what you've just done? About a month ago, Jeremy Miller talked about an IOC container detente and how there should be a common interface among IoC frameworks:

    http://codebetter.com/blogs/jeremy.miller/archi...

    I know you wrote the IOC adapters in your test project so that you can test the various IoC frameworks, but what you've effectively done here is unify the more common IoC frameworks under one set of interfaces!

    In theory, I could easily swap to and from any one of those frameworks without having to worry about which IoC container I'm actually using. Again, awesome job!
  • Thanks. I thought the test adapters I did are too raw to be very useful -- no fluent interface, and probably not all basic features covered.
    However it would be nice if it actually helps you.
  • Btw, what exactly is Unregistered Resolution? Is that the ability to arbitrarily return services from concrete types not registered in the container?

    I've been working on my own container (LinFu.IoC 2.0) and it passes all of the 'MustHave' tests, but I can't seem to figure out what the intent was behind the Unregistered Resolution feature.

    What makes it interesting is that I can even determine which services exist inside the container and I can instantiate them all at once, like so:

    // Instantiate all named services of type 'IMyService'
    var services = from info in container.AvailableServices
    where info.Name.Length > 0 &&
    info.ServiceType == typeof(IMyService)
    select container.GetService(info) as IMyService;

    You can check it out here:

    http://code.google.com/p/linfu/wiki/BuildingLinFu2

    Right now, it's still under development, but I'm only two features away from making it available for production usage. Take a look! :)
  • Unregistered Resolution is an ability to reuse container resolution logic for a given concrete type, without polluting the container itself with this type.
    It is very useful when framework also provides support for additional arguments -- then I can easily build a factory that reuses container dependency resolution.
    See http://blog.ashmind.com/index.php/2008/06/23/di... for an example.

    I think other solution is to create a quick throwable-out child container like autofac provides, but I have not tried this yet (sounds like a much less performant solution).

    I have added you as a project member to the net-ioc-frameworks, so you now probably have access to upload LinFu adapter.
  • Unregistered Resolution is an ability to reuse container resolution logic for a given concrete type, without polluting the container itself with this type.

    Ahh, I see! Now that you've mentioned it, LinFu *does* support unregistered resolution, but its not implemented quite the same way as other contains would implement it. For example, if I had an unregistered class like:

    public class MyClass
    {
    public MyClass(ISomeService service)
    {
    // ...
    }
    }

    You can create the unregistered class in LinFu using the following code:

    // ...construct the container somewhere here
    container.AddService<ISomeService>(new SomeService());
    var myClass = (MyClass)container.AutoCreate(typeof(MyClass);

    Now the tricky part here is that I've been running LinFu through your battery of tests, and I can't seem to get it to pass the UnregisteredResolution test. Is there anyway to modify the logic so that each library has a way to implement their own unregistered resolution? Clumping it all under a single Adapter.Resolve() call doesn't seem to apply, in this case.
  • Sure, it's a thing I forgot to do correctly.
    There is already a Create<T> method in the IFrameworkAdapter, but test did not use it.
    I have just modified the test to use Create<T> instead of Resolve<T>.

    So get the latest version, then implement Create<T> using AutoCreate.
  • Thanks, Andrey! I went ahead and added the LinFuAdapter to the test suite.

    Btw, you might want to add property service list injection as one of the "should haves" for IoC container features. For example, if I have a service instance with a property such as:

    [SomeCustomPropertyInjectionAttribute] // This differs with every IoC container
    public ISomeServices[] MyServices { get; set; }

    It would be nice to have the container automatically instantiate the existing list of ISomeService instances from the container and inject it to the MyServices property. What do you think?
  • Good idea! I supposed that all frameworks that support list injection for constructors support them for properties as well.
    But documenting assumptions this in a testable way is always a good idea. I'll do this.
  • Hi Andrey,

    Wow! It is very interesting to see a methodical approach to this comparison.

    Autofac does also support list registrations - but like 'resolve anything' you have to opt-in. See: http://code.google.com/p/autofac/wiki/Collections.

    As you've hinted at - like most containers you can change this behaviour by writing custom extensions. In general, you'll find Autofac is very conservative about working absolutely predictably by default.

    Cheers,

    Nick
  • Thanks!

    You have a very interesting implementation.
    I would prefer to have an automatic registration by default, since if I get into situation where I would need more than one ILogger collection, I would probably use some kind of contextual override for a requiring component anyway. But it is a question of preference.

    There are only two things that I feel are missing in your implementation -- support for IService[] (since it is simplest way to define collection dependency) and and ability to register collections using non-generic API.

    Due to the first one, I can not update tests to pass right now, however, I had fixed the chart and will fix the post text as well.
  • On IService[] - point taken, issue raised. In the meantime you can do:

    builder.Register(c => c.Resolve<IEnumerable<X>>().ToArray());

    ..in order to adapt the default collection type onto an array type.

    I'll look into the non-generic collection registrations - may look into that in the future if there is demand.

    Thanks for the feedback!
  • Aaah - and regarding automatic registration - you can always do:

    builder.RegisterTypesAssignableTo<object>();

    :) Not really recommendable though.

    I recently ported some Prism code from Unity to Autofac, and used something similar to:

    builder.RegisterTypesMatching(t => t.Name.EndsWith("View"));

    --- just to illustrate that there is no need to use tagging interfaces or inheritance in order to work with this feature.
  • Sure, I like the second approach much more.

    By the way, is it possible to resolve unregistered types in Autofac?
    I do not feel that is very important, given hierarchical containers, but I am still interested.
  • The net effect is almost the same. RegisterTypesMatching() and RegisterTypesAssignableTo() are lazy - there is no scan of loaded assemblies, for instance.

    You could always create an extension method ResolveUnregistered() which could check/register first, too.

    Not sure what you mean about hierarchical containers relating to this use case - can you clarify a little?
  • The use case is to create a factory which registers several factory-specific components without polluting the original container with these components and their local scope dependencies (such as connection data). I describe the problem in detail at http://blog.ashmind.com/index.php/2008/06/23/di... .

    So, if I can create a container in place and then throw it away, it also solves the pollution problem.
  • Good review, thanks for taking the time to do it.
  • Great review! This is exactly what I was looking for to help clear things up for me.
  • Really like the overview and nice comparison too!
  • Fantastic comparison. Thanks for sharing

Add New Comment

Returning? Login