Dynamic Dependency Injection at The Run Time

23 Views Asked by At

i have the following classes

public class GetTestByIdQuery : ICqrsQuery<JustTestDto>
{
    public Guid JustTestId { get; set; }

    public GetTestByIdQuery(Guid justTestId)
    {
    JustTestId = justTestId;
    }
}

and

public class ListTestsQuery : ICqrsQuery<List<JustTestDto>>
{
}

how can i register them dynamically at the run time using reflection by getting all the classes that implements the interfaces ICqrsQuery and ICqrsQuery<T> ?

i already wrote the following code

public static IServiceCollection AddCqrsQueries(this IServiceCollection services)
{
    var assembly = Assembly.GetExecutingAssembly();

    var queries = assembly.GetTypes()
        .Where(t => t.IsClass && !t.IsAbstract &&
                    t.GetInterfaces().Any(i => i.IsGenericType &&
                    i.GetGenericTypeDefinition() == typeof(ICqrsQuery<>)));

    foreach (var query in queries)
    {
        var interfaces = query.GetInterfaces();
        foreach (var @interface in interfaces)
        {
            if (@interface.IsGenericType
                && @interface.GetGenericTypeDefinition() == typeof(ICqrsQuery<>))
            {
                var constructor = query.GetConstructors().FirstOrDefault();
                var constParameters = constructor?.GetParameters() ?? null;
                var parameterValues =
                    constParameters != null ? new object[constParameters.Length] : null;

                if (parameterValues?.Length > 0 && parameterValues != null)
                {
                    for (int i = 0; i < constParameters.Length; i++)
                    {
                        parameterValues[i] = services.BuildServiceProvider()
                            .GetService(constParameters[i].ParameterType);
                    }

                    services.AddTransient(serviceProvider =>
                    {
                        var instance = Activator.CreateInstance(query, parameterValues);
                        return instance;
                    });
                }
                else
                {
                    ///no parameters
                    services.AddTransient(query);
                }
            }
        }
    }
    return services;
}

it works fine with the classes that has no parameters such as ListTestsQuery but for classes with constructor parameters it doesn't such as GetTestByIdQuery

i have notice that the problem is with var instance = Activator.CreateInstance(query, parameterValues); since its return type is object? although at run time its evaluated to GetTestByIdQuery, if i do explicit casting to type GetTestByIdQuery it works otherwise it doesn't

How can I solve this problem?

0

There are 0 best solutions below