Search code examples
c#.net-coreinversion-of-control

Dependency Injection: call different services based on the environment


I'm building a .net core 3.1 web application and I'm experimenting with the builtin dependency injection.

I would like to inject a different service based on the runtime environment in which the application is running, I thought that I could use an attribute to define if the service is suitable for the environment, for example:

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddTransient<IOperation, OperationDevelopment>();
    services.AddTransient<IOperation, OperationStaging>();
    services.AddTransient<IOperation, OperationProduction>();

    ...
}


public interface IOperation
{
    Guid OperationId { get; }
}

[Development]
public class OperationDevelopment : IOperation
{
}

[Staging]
public class OperationStaging : IOperation
{
}

[Production]
public class OperationProduction : IOperation
{
}

What should I do, skip the registration? Register all and then resolve the suitable service? Something that I missed?

If the .net core DI is too basic, what should I use?

Thanks


Solution

  • You could do something like this:

    interface IOperationAttribute
    {
    }
    
    [Development]
    public class OperationDevelopment : IOperation
    {
        public Guid OperationId { get; }
    }
    
    public class DevelopmentAttribute : Attribute, IOperationAttribute
    {
    }
    

    Add a new extension for IServiceCollection

    public static class AppServiceExtension
    {    
        public static IServiceCollection AppOperationServices(this IServiceCollection services)
        {
            var typesWithOperationAttribute =
                from a in AppDomain.CurrentDomain.GetAssemblies()
                from t in a.GetTypes()
                let attributes = t.GetCustomAttributes(typeof(IOperationAttribute), true)
                where attributes != null && attributes.Length > 0
                select new { Type = t };
    
            foreach (var item in typesWithOperationAttribute)
                services.AddTransient((Type)item.Type);
    
            return services;
        }
    }
    

    And in ConfigureServices just call

    services.AppOperationServices();