简体   繁体   中英

Autofac. Retrieve all services registered as named

I am trying to use named registration in the program. But example from documentation does not work. http://autofac.readthedocs.org/en/latest/advanced/keyed-services.html#named-services

public class DbLoggerModule : Autofac.Module
{
protected override void Load(Autofac.ContainerBuilder builder)
{
builder.Register<DbLogger>().Named<ILogger>("1");
}

and got compilation error: No overload for method 'Register' takes 0 arguments

I also tried the following variants:

builder.RegisterType<DbLogger>().Named<ILogger>("1");
builder.RegisterType<DbLogger>().Named<ILogger>("1").As<ILogger>();
builder.RegisterType<DbLogger>().Named<ILogger>("1").As<ILogger>();
builder.RegisterType<DbLogger>().As<ILogger>().Named<ILogger>("1");            

They do not cause a compile error. But as it is not impossible to obtain a given named service:

  1. var lll = _сontainer.ResolveNamed< ILogger >("1");

throws an exception: The requested service '1 (Console1.ILogger)' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.

  1. IEnumerable loggers = _сontainer.Resolve< IEnumerable< ILogger > >();

Returns an empty list

UPDATE

Part of the problem was solved. During the experiments, I have created a few interfaces with similar names. As a result, I register one interface, but resolved other.

Now this line is working:

var lll = _сontainer.ResolveNamed< ILogger >("1");

However, I can not get a complete list of classes that implement the interface:

var lll = _сontainer.ResolveNamed<ILogger>("1");
lll.Log(null);   // working !
IEnumerable< ILogger >loggers=_сontainer.Resolve<IEnumerable< ILogger >>();// It returns an empty list

ALSO

When I refuse to named services, the programm begins to work:

builder.RegisterType<DbLogger>().As<ILogger>();
...
_сontainer.Resolve<IEnumerable<ILogger>>(); // working !

I suspect that we can not get a list of services registered as named. Someone can confirm this?

UPDATE 2 Here is a very simple but complete example. It does not work. Why ?

public interface ISimpleService
{
    string Test();
}
public class SimpleService1 : ISimpleService
{
    public string Test()
    {
        return "Hello World from SimpleService1";
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        {
            builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff");
        }

        IContainer container = builder.Build();

        var services = container.Resolve<IEnumerable<ISimpleService>>();

        Console.WriteLine(services.Count()); // 0. Why ?
    }
}

You are trying to resolve ISimpleService (interface), but SimpleService1 registered only as class (because the named registration), not as interface.

Try this:

builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff").As<ISimpleService>();

or

builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff").AsImplementedInterfaces();

A fully working example:

public interface ISimpleService
    {
        string Test();
    }
    public class SimpleService1 : ISimpleService
    {
        public string Test()
        {
            return "Hello World from SimpleService1";
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            var builder = new ContainerBuilder();
            {
                builder.RegisterType<SimpleService1>().Named<ISimpleService>("fff").As<ISimpleService>();
            }

            IContainer container = builder.Build();

            var services = container.Resolve<IEnumerable<ISimpleService>>();

            Console.WriteLine(services.Count()); // 1.
        }
    }

Initial sample will work if resolve ISimpleService by name:

var services = container.ResolveNamed<IEnumerable<ISimpleService>>("fff");

Your code should work.

Are you sure you have registered your module in your container?

Ensure something like this when bootstrapping your container (assembly scanning or plain registration):

// This example being fx a console app    
containerBuilder.RegisterAssemblyModules(Assembly.GetExecutingAssembly());

// Basic registration    
containerBuilder.RegisterModule<LoggerModule>();

// Ensure the container is build
_container = containerBuilder.Build();

If you want to resolve a list of named (and only those, no the ones registered with a name and without, as suggested in other answers, here is what you can do:

builder.RegisterType<Foo>().Named<IFoo>("IFoo").SingleInstance();
builder.RegisterType<Foo2>().Named<IFoo>("IFoo").SingleInstance();
builder.RegisterType<Foo3>().Named<IFoo>("2").As<IFoo>().SingleInstance();

var container = builder.Build();

//Will resolve type Foo2
var foo = container.ResolveNamed<IFoo>("IFoo");

//Will resolve 2 IFoo: Foo and Foo2
var foos = container.ResolveNamed<IEnumerable<IFoo>>("IFoo");

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM