Search code examples
dependency-injectionninjectunity-containerlight-inject

LightInject vs (Ninject and Unity) Unregistered Type Resolution


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>();
    }

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)