Dependency Injection Auto Registration

The following paragraph is from the aurelia documentation:

Imagine that we have a single instance of Container called root . If a developer (or Aurelia) invokes root.get(A) to resolve an instance of A , the root will first check to see if it has a Resolver for A . If one is found, the Resolver is used to get the instance, which is then returned to the developer. If one is not found, the container will auto-register a Resolver for A . This resolver is configured with a singleton lifetime behavior. Immediately after auto-registration, the Resolver is used to get the instance of A which is returned to the developer. Subsequent calls to root.get(A) will now immediately find a Resolver for A which will return the singleton instance.

Regarding the bold marked sentence, is it possible to deactivate this behaviour (auto-registration)? In my opinion, this behavior is very error-prone when a forgotten dependency is automatically registered without anyone noticing.

2 Likes

Hi @elitastic,

Your question is interesting. I am not an expert regarding Aurelia’s dependency injection mechanism, but I will try to reason about the logic as far as I can understand it currently.

First of all, if a resolver for type A is auto-registered by a DI-container, it seems to me that type A is actively used in a DI-scenario somewhere in your app. Either you use it in a constructor where it gets injected, or you explicitly use the DI-container’s get method. So I do not really understand what you mean with a “forgotten dependency”. A correct linting configuration and/or some specific searches within your IDE/editor might suffice to detect them.

But suppose that the auto-registration behavior could be disabled. How would the DI container behave in runtime? You would probably need to explicitly register all your injectable types using Aurelia’s Container Registration API. Injecting a type in a class constructor that does not have an explicitly registered resolver would probably result in injecting undefined. I’m not sure if that would be very helpful.

According to the documentation, singleton lifetime behavior is a fitting default behavior in the Aurelia architecture. But in scenarios where you don’t want singleton lifetime of your class instances, you could still use explicit resolver registrations in your DI container(s).

I assume you might want to have more explicit control over which types can effectively be injected. Or perhaps you want to avoid that a certain type can be injected at all. I’m not sure if this is possible. Regarding the latter case, you might try to implement your own custom resolver and register that resolver explicitly for your problematic type(s). I haven’t done such thing yet myself, so I am not aware of the (dis)advantages of such an approach.

At the moment, I am personally very happy with the current DI behavior, which allows me to create a correctly functioning app with a minimum of explicit coding. But it would be very interesting to learn in which scenarios the DI auto-registration mechanism would actually create a hard-to-track runtime failure regarding forgotten dependencies. Can you please provide a straightforward example for your issues with the current problematic DI auto-registration behavior?

3 Likes