Question

This may be obvious to some, but... Is there a way to resolve non-registered types with LightInject? Also, is it good practice to auto-magically resolve objects with DI frameworks without explicit injections for readability?

In my examples, I'm comparing super full featured frameworks (and possibly the slowest) to the one of the Lightest (and fastest) frameworks. That wasn't exactly a mistake :D

Constructor Injection (No Container)

    private static void ComposeObjects()
    {
        var repository = new CSVRepository();
        var viewModel = new PeopleViewerViewModel(repository);
        Application.Current.MainWindow = new PeopleViewerWindow(viewModel);
    }

Ninject

    private void ConfigureContainer()
    {
        Container = new StandardKernel();
        Container.Bind<IPersonRepository>().To<CSVRepository>()
            .InSingletonScope();
    }

    private void ComposeObjects()
    {
        Application.Current.MainWindow = Container.Get<PeopleViewerWindow>();
    }

Unity

    private void ConfigureContainer()
    {
        Container = new UnityContainer();
        Container.RegisterType<IPersonRepository, CSVRepository>(
            new ContainerControlledLifetimeManager());
    }

    private void ComposeObjects()
    {
        Application.Current.MainWindow = Container.Resolve<PeopleViewerWindow>();
    }

LightInject

    private void ConfigureContainer()
    {
        Container = new ServiceContainer();
        Container.Register<IPersonRepository, CSVRepository>(
            new PerContainerLifetime());

        // Do we need to explicitly register PeopleViewerWindow with LightInject?

        Container.Register<PeopleViewerWindow>(
          factory =>
            new PeopleViewerWindow(new PeopleViewerViewModel
              (Container.GetInstance<IPersonRepository>()))
          );
    }

    private void ComposeObjects()
    {
        Application.Current.MainWindow = Container.GetInstance<PeopleViewerWindow>();
    }
Was it helpful?

Solution

LightInject can resolve services that are not registered with the container using the RegisterFallback method.

var container = new ServiceContainer();
container.RegisterFallback((type, s) => true, request => new Foo());
var foo = container.GetInstance<IFoo>();

The first argument to the RegisterFallback method makes it possible to possible to decide if the service can be "late-resolved". The second argument is a ServiceRequest instance that provides the requested service type and service name.

The documentation has been updated with this information. http://www.lightinject.net/

UPDATE

Based on your sample code I suspect that your are trying to overcome the fact that LightInject does not automatically resolve unknown concrete types.

For your current scenario I think it would be best to scan assemblies and search for concrete types that inherits from a certain type. For instance classes that inherits from some kind if viewmodel base class.

Take a look at this code from LightInject.WebApi that uses a similar approach to register controllers.

public static void RegisterApiControllers(this IServiceRegistry serviceRegistry, params Assembly[] assemblies)
{
    foreach (var assembly in assemblies)
    {
        var controllerTypes = assembly.GetTypes().Where(t => !t.IsAbstract && typeof(IHttpController).IsAssignableFrom(t));
        foreach (var controllerType in controllerTypes)
        {
            serviceRegistry.Register(controllerType, new PerRequestLifeTime());
        }
    }
}

Best regards

Bernhard Richter (author of LightInject)

OTHER TIPS

I'm not that familiar with LightInject, so I don't know whether it is possible to resolve unregistered types, but I can answer this:

is it good practice to auto-magically resolve objects with DI frameworks without explicit injections for readability?

I think it is fine to use unregistered type resolution to resolve unregistered types. In some scenarios it even makes no sense to not use it, for instance when registering an open-generic type. Without this you will have to register every closes-generic mapping explicitly which causes you to make constant changes to your composition root (or you need to do some sort of batch registration where you go search for all the types that can be used as type arguments in your generic type and build the closed-generic versions using reflection and registering them, yuck).

What you however should always try to achieve is to have verifiable DI configuration. It should be possible to verify the container's configuration during application startup or using a unit test. IMO it is crucial to test this, because you need to compensate the loss of compile-time support that you get by introducing Dependency Injection. You can test this either by iterating the container's configuration and requesting asking the container to resolve each registration (some DI libraries contain functionality to help you with this), or you ask the container to resolve all root types explicitly.

If you chose to iterate the entire configuration, this means that at least all root types (the types that you resolve directly from the container, for instance your MVC controllers, ASP.NET Page classes or WPF Window classes) need to be registered in the container. Otherwise the container knows nothing about that type and it will therefore not be tested and you end up with a system that can still fail at runtime.

If you instead chose to iterate all root types, it saves you from having to register them explicitly, but you still need a way to find all your root types through reflection. If you don't do it through reflection, it means you will have to change your unit test every time you add a new root type. And you will sometimes forget to change your test causing your configuration to be verified only partly. That's something to prevent.

So my preference is to register root types explicitly and this might have other advantages. Some DI libraries contain very useful diagnostic tooling that tell you all kinds of interesting information about your object graph, and can warn you about common misconfigurations (such as Captive Dependencies). These tools can obviously only do its job on types that the library knows about. The library can often find registrations that are not explicitly registered, as long as they are a dependency of some other registered type, but this of course doesn't hold for root types.

As you do with Unity and Ninject I don't see a default strategy that would resolve the related dependencies as such for LightInject. I'm not experience in LightInject but at least their documentation does not have a sample like that. There might other ways to achieve this as scanning assemblies, but I would explicitly inject it as below. It would resolve the PeopleViewerWindow instance as required.

        var lightContainer = new ServiceContainer();
        lightContainer.Register<IPersonRepository, CSVRepository>
        (new PerContainerLifetime());
        lightContainer.Register<PeopleViewerWindow>(
            factory =>
                new PeopleViewerWindow(new PeopleViewerViewModel
                (lightContainer.GetInstance<IPersonRepository>())));

        var instance2 = lightContainer.GetInstance<PeopleViewerWindow>();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top