开发者

Is it possible in Autofac to resolve all services for a type, even if they were registered with a name or key?

In Autofac one can do the following to get all registered servi开发者_如何学运维ces:

IEnumerable<MyClass> all = Context.Resolve<IEnumerable<MyClass>>()

However, this does not include those which were registered as named services.

Looking at the Autofac source it seems this is because services are queried for resolution based on either a TypedService or a KeyedService.

Is there a way to resolve all services to an IEnumerable, irrespective of whether they were registered with a name or not?


The best option here is to register the items using both the key and the regular 'typed' service:

builder.Register<CupOfT>()
    .As<IBeverage>()
    .Keyed<IBeverage>("someKey");

You can then just resolve IEnumerable<IBeverage> to get the result you're after, while resolving them by key (or name) is also supported.

If you're concerned about maintaining a particular default registration for IBeverage just use PreseveExistingDefaults() on the others (or make sure your intended default is registered last).

HTH!

Nick


I've written a method which appears to work; I'd appreciate feedback if there's a built-in way to do this in Autofac. In the below example, the field _context is of type IComponentContext.

    public IEnumerable<T> ResolveAll<T>()
    {
        // We're going to find each service which was registered
        // with a key, and for those which match the type T we'll store the key
        // and later supplement the default output with individual resolve calls to those
        // keyed services
        var allKeys = new List<object>();
        foreach (var componentRegistration in _context.ComponentRegistry.Registrations)
        {
            // Get the services which match the KeyedService type
            var typedServices = componentRegistration.Services.Where(x => x is KeyedService).Cast<KeyedService>();
            // Add the key to our list so long as the registration is for the correct type T
            allKeys.AddRange(typedServices.Where(y => y.ServiceType == typeof (T)).Select(x => x.ServiceKey));
        }

        // Get the default resolution output which resolves all un-keyed services
        var allUnKeyedServices = new List<T>(_context.Resolve<IEnumerable<T>>());
        // Add the ones which were registered with a key
        allUnKeyedServices.AddRange(allKeys.Select(key => _context.ResolveKeyed<T>(key)));

        // Return the total resultset
        return allUnKeyedServices;
    }


It would appear that you can combine the As<T>() methods and Named<T>() methods as shown below:

    [TestMethod]
    public void ResolveTests()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<ClassA1>().As<IClassA>().Named<IClassA>("1");
        builder.RegisterType<ClassA2>().As<IClassA>().Named<IClassA>("2");
        builder.RegisterType<ClassA3>().As<IClassA>().Named<IClassA>("3");
        var container = builder.Build();

        var allInstances = container.Resolve<IEnumerable<IClassA>>();
        allInstances.Count().Should().Be(3);

        container.ResolveNamed<IClassA>("1").Should().BeAssignableTo<ClassA1>();
        container.ResolveNamed<IClassA>("2").Should().BeAssignableTo<ClassA2>();
        container.ResolveNamed<IClassA>("3").Should().BeAssignableTo<ClassA3>();
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜