5

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");
Steven
  • 166,672
  • 24
  • 332
  • 435
achekh
  • 1,106
  • 7
  • 20

2 Answers2

13

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;
Nicholas Blumhardt
  • 30,271
  • 4
  • 90
  • 101
  • 1
    This worked for me as well. I don't believe that the Cast() is needed, however. – luksan Sep 19 '13 at 23:41
  • Thanks for spotting that, I think you're right. Some funky overload resolution going on for `As()` and no time to check it right now - did you have a chance to run it? – Nicholas Blumhardt Sep 22 '13 at 05:11
3

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();
luksan
  • 7,661
  • 3
  • 36
  • 38