Autofac RegisterAssemblyOpenGenericTypes matching query

57 Views Asked by At

I'm attempting to register all open generic components I tag with a custom attribute. The query finds the class correctly but the interface is not registered properly. I'm able to register and resolve the component fine using RegisterGeneric

**Working: **


/// <inheritdoc />
[GenericTransient]
public sealed class RetryPolicyService<TResult> : IRetryPolicyService<TResult>
{...
}

builder.RegisterGeneric(typeof(RetryPolicyService<>))
                .As(typeof(IRetryPolicyService<>))
                .InstancePerDependency();

Not Working:

builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
                .Where(t =>
                    t.GetCustomAttribute<GenericTransientAttribute>() != null)
                .As(t => t.GetInterfaces()[0]);

Not Working:

 builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
                .Where(t =>
                    t.GetCustomAttribute<GenericTransientAttribute>() != null)
                .AsImplementedInterfaces();

Break Point enter image description here

The expectation is to be able to inject IRetryPolicyService into objects. Again its working as expected when I register the type specifically.

private readonly IHttpClientService _httpClient;
private readonly IRetryPolicyService<HttpResponseMessage> _retryPolicy;

public ServiceController(
    IHttpClientService httpClient,
    IRetryPolicyService<HttpResponseMessage> retryPolicy)
{
    _httpClient = httpClient;
    _retryPolicy = retryPolicy;
    _retryPolicy.CreatePolicy(5, times => TimeSpan.FromMilliseconds(times * 1000));
}
1

There are 1 best solutions below

1
Mike Mozhaev On BEST ANSWER

The following simplified example works fine. If you uncomment GenericTransient attribute on the second service then controller will get its instance (last registration wins). And the retryPolicies variable will get 2 instances.

The first variant (with GetInterfaces()) also worked after adding .GetGenericTypeDefinition().

using Autofac;
using System.Reflection;

namespace Console.Core6
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var builder = new ContainerBuilder();

            builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
                .Where(t => t.GetCustomAttribute<GenericTransientAttribute>() != null)
                .AsImplementedInterfaces();

            builder.RegisterAssemblyOpenGenericTypes(Assembly.GetExecutingAssembly())
                .Where(t => t.GetCustomAttribute<GenericTransientAttribute>() != null)
                .As(t => t.GetInterfaces()[0].GetGenericTypeDefinition());

            builder.RegisterType<ServiceController>().InstancePerDependency();

            var container = builder.Build();
            var controller = container.Resolve<ServiceController>();
            var retryPolicies = container.Resolve<IEnumerable<IRetryPolicyService<HttpResponseMessage>>>();
        }
    }

    internal class GenericTransientAttribute : Attribute
    { }

    public interface IRetryPolicyService<TResult>
    { }

    [GenericTransient]
    public sealed class RetryPolicyService<TResult> : IRetryPolicyService<TResult>
    {}

    //[GenericTransient]
    public sealed class RetryPolicyService2<TResult> : IRetryPolicyService<TResult>
    {}

    public class ServiceController
    {
        private readonly IRetryPolicyService<HttpResponseMessage> _retryPolicy;

        public ServiceController(IRetryPolicyService<HttpResponseMessage> retryPolicy)
        {
            _retryPolicy = retryPolicy;
        }
    }
}