Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Autofac decorating open generics registered using assembly scanning

I'm trying to apply autofac decorator support feature to my scenario with no success. It looks like in my case it doesn't assign the name to the registrations properly.

Is there a way to register scanned assembly types with a name, so that I can later use it in the open generic decorator key?

Or maybe I'm completely wrong and doing something inappropriate here?

builder.RegisterAssemblyTypes(typeof(IAggregateRepositoryAssembly).Assembly)
    .AsClosedTypesOf(typeof(IAggregateViewRepository<>)) //here I need name, probably
    .Named("view-implementor", typeof(IAggregateViewRepository<>))
    .SingleInstance();

builder.RegisterGenericDecorator(typeof(CachedAggregateViewRepository<>),
    typeof(IAggregateViewRepository<>), fromKey: "view-implementor");
like image 291
achekh Avatar asked Nov 15 '11 17:11

achekh


2 Answers

Here's an attempt, not in front of Visual Studio so overload resolution might not be exactly right:

builder.RegisterAssemblyTypes(typeof(IAggregateRepositoryAssembly).Assembly)
    .As(t => t.GetInterfaces()
              .Where(i => i.IsClosedTypeOf(typeof(IAggregateViewRepository<>))
              .Select(i => new KeyedService("view-implementor", i))
              .Cast<Service>())
    .SingleInstance();
  • Named() is just syntactic sugar for Keyed(), which associates the component with a KeyedService
  • As() accepts a Func<Type, IEnumerable<Service>>

You will also need:

using Autofac;
using Autofac.Core;
like image 178
Nicholas Blumhardt Avatar answered Oct 01 '22 03:10

Nicholas Blumhardt


If you wanted to clean up your registration code you could also define the following additional extension method (very verbose and based on the autofac source for the other overload, but it only needs to be defined once):

using Autofac;
using Autofac.Builder;
using Autofac.Core;
using Autofac.Features.Scanning;

public static class AutoFacExtensions
{
    public static IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle>
        AsClosedTypesOf<TLimit, TScanningActivatorData, TRegistrationStyle>(
            this IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> registration,
            Type openGenericServiceType,
            object key)
        where TScanningActivatorData : ScanningActivatorData
    {
        if (openGenericServiceType == null) throw new ArgumentNullException("openGenericServiceType");

        return registration.As(t => 
            new[] { t }
            .Concat(t.GetInterfaces())
            .Where(i => i.IsClosedTypeOf(openGenericServiceType))
            .Select(i => new KeyedService(key, i)));
    }
} 

That would allow you to simply do this:

builder.RegisterAssemblyTypes(typeof(IAggregateRepositoryAssembly).Assembly)
    .AsClosedTypesOf(typeof(IAggregateViewRepository<>), "view-implementor")
    .SingleInstance();
like image 35
luksan Avatar answered Oct 01 '22 01:10

luksan