Skip to content

Lazy VariantServiceProvider #564

Open

Description

Currently, when you use IVariantServiceProvider to resolve a service type variant it instantiates all configured service variants prior to resolve the selected one.
Ideally we'd want to lazy instantiate the resolved service only.

My use case is, I've got several implementations for a given interface, each requires a unique set of configuration properties and dependencies. If I configure my app to always resolve to a single variant I don't want to have all settings and dependencies available for the other implementations that I'm not using.

At the moment all my implementations must be configured and they are all loaded into memory prior to resolve the instance.

Activity

  1. zhiyuanliang-ms commented on Nov 24, 2025

    @zhiyuanliang-ms
    Member

    Hi, Olavo Castro (@olavopeixoto)
    Sorry for the late response. Unfortunately, the current design of variant service provider cannot achieve the lazy instantiation. There is no proper API from ActivatorUtilities to get instance from DI container when the service is registered through factory method.

    If you take a look at PR #567, the implementation is actually fighting against the .NET DI system. See this comment for more information.

    .NET 8 introduced "Keyed Service". This feature is a perfect match for the concept of variant service.

    For example, user can register keyed service:

    builder.Services.AddKeyedSingleton<ICache, BigCache>("big");
    builder.Services.AddKeyedSingleton<ICache, SmallCache>("small");
    
    builder.Services.AddFeatureManagement()
           .WithVariantService<ICache>("CacheVariantFeature");

    And the variant service provider only need to call ServiceProvider.GetKeyedService("variant-name"). It can achieve the lazy instantiation goal.

    However, the feature management library is targeted on netstandard. There is not a clean solution for us to adapt the variant service provider to the implementation that uses keyed service registration, which is very unfortunate.

    The solution we are considering now is to offer a new interface

    public interface INamedServiceProvider<TService>
    {
        TService GetService(string name);
    }

    The VariantServiceProvider will use INamedServiceProvider to retrieve variant service if it could be found in the DI container. Otherwise, it will still get IEnumerable<TService> from DI and pick the correct intance based on the allocated variant.

    Any thought or feedback is welcome. Thank you for your understanding!

  2. Stepami commented on May 13, 2026

    @Stepami

    Zhiyuan Liang (@zhiyuanliang-ms) why don't you use package-provided keyed di?

    <Project Sdk="Microsoft.NET.Sdk">
    
        <PropertyGroup>
            <TargetFramework>netstandard2.0</TargetFramework>
        </PropertyGroup>
    
        <ItemGroup>
          <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
        </ItemGroup>
    
    </Project>
    
  3. zhiyuanliang-ms commented on May 14, 2026

    @zhiyuanliang-ms
    Member

    Hey, Степан (@Stepami) Thanks for reaching out.

    Do you mean we offer different functions fro netstand2.0 and .net 8+?

  4. Stepami commented on May 14, 2026

    @Stepami

    Zhiyuan Liang (@zhiyuanliang-ms) Despite the feature management library is targeted on netstandard Keyed DI can still be used through package.

    Moreover there are already 8.0.x packages referenced in the feature management library

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions