简体   繁体   中英

Autofac register and resolve with Names

I'm trying to register objects by their names, and later on take them in another type's ctor as parameters, during registration.

Hope my example will be clear enough, here it is:

public class Obj : IObj
{
    public class Obj(string name)
}

I register the following objects like this :


public void RegisterMyObj(string name)
{
    // Keyed with the object name
    builder.Register<Obj>().Named<IObj>(name).WithParameter(name).SingleInstance();
}

public class ObjectsHolder : IObjectsHolder
{
    public ObjectsHolder (List<IObj> objsToHold))
}

// I want to register my ObjectsHolder in the following way:
for example, this is how I want to call it from my code: 
    RegisterObjectsHolder(string Obj1Name, string Obj2Name)

public void RegisterObjectsHolder(params string[] objectsNames)
{
    builder.Register<IObjectsHolder>().WithParameters(// Here comes the magic code which I can't figure out. 
                                                      // I want objects holder to be registered with the Obj instances whose names were passed to this method, 
                                                      // is there a way to do this?)
                                                      )
}   

I'm not strict about the ways the registrations will look.. If you know of a way to accomplish this using different methods, that will also do.

Thanks in advance!

Instead of registering your services as "named", you may want to use "keyed" services. There is no way to specify services by their names. But you can use IIndex<TKey, TService> to retrieve a dictionary-like object with keyed services of specified type. So you can register:

builder.RegisterType<Service1>().Keyed<IService>("key1");
builder.RegisterType<Service2>().Keyed<IService>("key2");
builder.RegisterType<Service3>().Keyed<IService>("key3");
builder.RegisterType<Service4>().Keyed<IService>("key4");
builder.RegisterType<Service5>().Keyed<IService>("key5");

Later, in your constructor, you can inject:

public Test(IIndex<string, IService> serviceDictionary)
{
    var service1 = serviceDictionary["key1"];
}

I used string objects as keys, but you can introduce eg enum and use it as a key.

EDIT:

If you want to narrow down available services for some classes, you can eg introduce different enum types as keys.

enum ServicesA { A1, A2, A3 }
enum ServicesB { B1, B2 }

Then, registratrions:

builder.RegisterType<Service1>().Keyed<IService>(ServicesA.A1);
builder.RegisterType<Service2>().Keyed<IService>(ServicesA.A2);
builder.RegisterType<Service3>().Keyed<IService>(ServicesA.A3);
builder.RegisterType<Service4>().Keyed<IService>(ServicesB.B1);
builder.RegisterType<Service5>().Keyed<IService>(ServicesB.B2);

Now, if you inject IIndex<SerivcesA, IService> , only Service1 , Service2 and Service3 would be available, for IIndex<SerivcesB, IService> it would be Service4 and Service5 .

You can chain Keyed registration so if you join both registrations from above to

builder.RegisterType<Service1>().Keyed<IService>(ServicesA.A1).Keyed<IService>("key1");` 

etc., you could use both IIndex<YourEnum, IService> with only some of IService implementations or IIndex<string, IService> with all of them.

I like to register by naming convention.

 var assembly = Assembly.GetExecutingAssembly();
 builder.RegisterAssemblyTypes(assembly).Where(t => t.Name.EndsWith("Service")).AsImplementedInterfaces().InstancePerLifetimeScope();

Then just place the dependencies in the constructor.

 private IUserService UserService { get; set; }
    public UserController(IUserService userService)
    {
        UserService = userService;
    }

This way I only need to stick to my naming conventions to get the job done. Honestly after initial setup of a project, I rarely need to look at autofac again.

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