LightInject: LightInject no longer overwrites registered services with new dependencies

In our project, our bootstrapping system supplies a set of default services via LightInject which users of the bootstrapper are free to overwrite with their own implementations. The following used to work a few months back:

[Test]
public void Test_Default_Service_Is_Overwritten()
{
    var container = new ServiceContainer();
    container.Register<IFoo, FooImpl>();
    var fooImpl = container.GetInstance<IFoo>();

    Assert.IsAssignableFrom(fooImpl, typeof(FooImpl));

    container.Register<IFoo, OtherFooImpl>();
    var otherFooImpl = container.GetInstance<IFoo>();

    Assert.IsAssignableFrom(otherFooImpl, typeof(OtherFooImpl));
}

However, this test now fails. It seems that there is no way of overwriting an existing service with a different implementation. Is this intended?

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 18 (6 by maintainers)

Commits related to this issue

Most upvoted comments

Bottom line here is that shared state between tests should be avoided. The cost of setting up the container for each test is negligible in most cases. Tests should be able to run in parallell in a non-deterministic order.

hi @tom3m,

I’m now trying to use DryIoc and there you even can specify behavior, what do you want to do when there is already a registration exist, do you want to append or you want to replace or etc. Replacing works perfectly at any stage. So I don’t see the reason why it can’t work in the LightInject.

I am author of DryIoc. And yes, the replacement works in DryIoc, but it is not free for your container setup. It may work for your specific case without any specific modifications to container and registrations, but you still should be aware of possible cache issues (the article is about Unregister but issues are the same). So for a good practice I would recommend avoid this feature if you can, or in other words do it if you know what you’re doing. Btw, even DryIoc has IContainer.WithNoMoreRegistrationAllowed method to make container resolve-only.

You can’t.

So the basic rule here is that you can add new services after the first request, but you cannot modify an existing service registration.

In your case you need to make sure that you allow for custom bootstrapping before the first request to the container is made.

Hi Tom,

You just describes why you need this, but not why you think this will actually work as expected in Unity. As I said, it won’t work in Unity, as it doesn’t work in any container. This problem is described in more detail here.

For your specific scenario, don’t reuse the same container instance for all integration tests. Even if it could work, it will cause concurrency conflicts when you run your tests in parallel. You should create a new container instance for each integration tests. Each test can add or override the registrations it requires for it test, but you will never have to be able to replace registrations when you already resolved from the container.

In case you might want to influence the used instance after the object graphs have been built (which is a quite common scenario), you can use proxies or composites that allow you to switch from one implementation to the other at runtime.

We’re moving away from old Unity and was going to use LightInject But the fact that it does not allows to override any dependency in any given moment make that not possible

Can you describe what you think exactly works in Unity, because overriding already resolved registrations are already resolved (both directly or indirectly) is riddled with bugs in every container. That’s why noth Ninject and Autofac are moving to a model where it becomes impossible to change the container after it has been built, and that’s why Simple Injector dissalowed this from day 1.