.netxamarin.formsdependency-injectionservicecollection

How to replace registrations (at runtime) after the ServiceCollection was built?


Is this still not supported, after 3 years? Looking at this question: .NET Core IServiceCollection Replace not refreshing

What I am trying to achieve in XamarinForms is a runtime replacement of a registered type (a data service) based on an interface by another one, after a user's choice.

I did find the Replace() extension function, but I did not find a way to fit it in.

Main reason being that after HostBuilder.ConfigureServices(), HostBuilder.Build() seems to be needed, but may be called only once. So how could a registration ever be changed?

Or is that still not intended? So, what's the use of Replace() then?

I am referring to Microsoft.Extensions.DependencyInjection.Extensions.ServiceCollectionDescriptorExtensions.Replace().


Solution

  • What you want to achieve is not supported. This is by design and it is unlikely that this will ever be supported. Being able to replace registrations at runtime leads to a lot of complexity inside the Container implementation, and can easily lead to multi-threading issues or simply unexpected behavior for the user. This is why newer versions of Autofac and Ninject have a similar design philosophy where replacing existing registrations after build is not allowed. Other DI Containers, such as Simple Injector, even applied this 'restriction' from their inception.

    The Simple Injector documentations contains a more-elaborate explanation on why it doesn't allow updating an already 'compiled' configuration. Although the text is written in the context of Simple Injector, the given examples are generic in nature and hold for all DI Containers.

    If you want to replace things at runtime, you should use a proxy implementation instead. How such proxy looks like depends on the requirements, but here's a simple example:

    services.AddTransient<ServiceA>();
    services.AddTransient<ServiceB>();
    services.AddTransient<IService, ProxyService>();
    
    public class ProxyService : IService
    {
        public ProxyService(ServiceA a, ServiceB b) ...
    
        public void SomeMethod()
        {
            if (some condition)
                this.a.SomeMethod();
            else
                this.b.SomeMethod();
        }
    }