JohanLarsson
JohanLarsson

Reputation: 485

AutoFac resolve interface for keyed registration

I am using AutoFac and am using the following lines in my registration

two different clases implement the same interface with two different keys..

_builder.RegisterType<CopyAppDataUserBudgetLine>().Keyed<ICopyAppData>(EntityType.UserBudgetLine).As<ICopyAppData>().InstancePerDependency();
_builder.RegisterType<CopyAppDataBudgetLine>().Keyed<ICopyAppData>(EntityType.BudgetLine).As<ICopyAppData>().InstancePerDependency();

same class registered with two different keys

_builder.RegisterType<RemoveOldAppData>().AsImplementedInterfaces().Keyed<IRemoveOldData>(EntityType.UserBudgetLine).InstancePerDependency();
_builder.RegisterType<RemoveOldAppData>().AsImplementedInterfaces().Keyed<IRemoveOldData>(EntityType.BudgetLine).InstancePerDependency();

Class definitions

public class RemoveOldAppData : RemoveAppDataBase, IRemoveOldData
    {
        public RemoveOldAppData(KonstruktEntities context, 
            ISQLQueryWhereClauseHelper sqlQueryWhereClauseHelper,
            IQueryExecutionHelper queryExecutionHelper) : base(context,sqlQueryWhereClauseHelper,queryExecutionHelper) { }
        public void RemoveBudgetLines(EntityType entityType, AccessEngine.LineAccessFilter filter)
        {
           ...
        }
    }

public class CopyAppDataBudgetLine : CopyAppDataBase , ICopyAppData
    {
        public CopyAppDataBudgetLine(KonstruktEntities context,
            ISQLQueryWhereClauseHelper sqlWhereClauseHelper,
            IQueryExecutionHelper queryExecutionHelper,
            ITableColumns columns) : base(context,sqlWhereClauseHelper,queryExecutionHelper,columns) { }

        public void CopyData(string receivingUserId, AccessEngine.LineAccessFilter queryFilter)
        {
            ...
        }
        public EntityType CopyDataEntityType
        {
            get;
            set;
        }
    }

Here is how I try to resolve these

using (var scope = _container.BeginLifetimeScope())
{
    var copyAppDataUserBudgetLine = scope.Resolve<ICopyAppData>();
    copyAppDataUserBudgetLine.CopyData("leif.andersson", filterAcccess);

Question: How do I resolve the above to take a specific EntityType (UserBudgetLine), do I have it in the constructor of the class or where else?

EDIT: I got it to work by using the following:

var copyAppDataUserBudgetLine = scope.ResolveKeyed<ICopyAppData>(EntityType.UserBudgetLine);

Is this the correct way or should I go about this differently?

Upvotes: 2

Views: 3006

Answers (2)

jonhoare
jonhoare

Reputation: 1309

I am assuming that EntityType is some Enum that you are keying the classes on?

When I resolve Keyed Interfaces I prefer to use a custom factory that takes in the constructor an IIndex from Autofac.

When this Factory is resolved by Autofac to me Autofac will serve me essentially a dictionary of my Types and their Keys.

I would achieve this by doing something like following which I have pseudo coded from your example...

public Enum EntityType
{
    UserBudgetLine,
    BudgetLine
}

public class EntityCopyAppDataFactory
{
    private readonly IIndex<EntityType, ICopyAppData> _copyAppDataIndex;

    public EntityCopyAppDataFactory(IIndex<EntityType, ICopyAppData> copyAppDataIndex)
    {
        _copyAppDataIndex = copyAppDataIndex;
    }

    public ICopyAppData GetCopyAppData(EntityType entityType)
    {
        return _copyAppDataIndex[entityType];
    }
}

And then register this factory in Autofac

builder.RegisterType<EntityCopyAppDataFactory>();

And then I would ask for my factory from Autofac and call GetCopyAppData with EntityType.UserBudgetLine that I require, either from scope as below or by Constructor Injection at the top of my stack.

using (var scope = _container.BeginLifetimeScope())
{
    var myFactory = scope.Resolve<EntityCopyAppDataFactory>();
    var copyAppDataUserBudgetLine = myFactory.GetCopyAppData(EntityType.UserBudgetLine);
}

I hope this gives you some food for thought about another direction perhaps rather than calling ResolveKeyed?

Upvotes: 0

JohanLarsson
JohanLarsson

Reputation: 485

This is what I ended up doing. This is one way to do it but I'd like to be able to always use scope.Resolve for all types of interfaces and not be forced to do scope.ResolveKeyed for these types of scenarios.

var copyAppDataUserBudgetLine = scope.ResolveKeyed<ICopyAppData>(EntityType.UserBudgetLine);

Upvotes: 1

Related Questions