Search code examples
c#entity-frameworkautofacdynamic-proxy

Resolve EF dynamic proxy in Autofac


I'm using Entity Framework and have registered some types for use in a factory class.

Registration is performed using Keyed like this:

builder.RegisterType<CreateTypeAStrategy>().Keyed<ICreateWorkItemsStrategy>(typeof(TypeA));

Here TypeA is an entity.

I resolve like this (action is of type TypeA):

var strategy = scope.ResolveKeyed<ICreateWorkItemsStrategy>(action.GetType(), new TypedParameter(action.GetType(), action));

I get the expected ComponentNotRegisteredException since the proxy isn't registered, only the concrete class is.

The interface and strategy is declared like this:

public interface ICreateWorkItemsStrategy
{
    IEnumerable<IWorkItem> CreateWorkItems();
}

public class CreateTypeAStrategy : ICreateWorkItemsStrategy
{
    public CreateTypeAStrategy(TypeA typeA)
    {

    }
    public IEnumerable<IWorkItem> CreateWorkItems()
    {
        throw new System.NotImplementedException();
    }
}

Any suggestions on how to resolve using a EF proxy?

Fully working example (needs EF and Autofac nuget):

public class ApplicationDbContext : DbContext
{
    public virtual DbSet<TypeA> TypeAs { get; set; }
    public virtual DbSet<RefForProxy> Refs { get; set; }
}

public class RefForProxy
{
    public int Id { get; set; }
}

public class TypeA
{
    public int Id { get; set; }
    public virtual RefForProxy Ref { get; set; }
}

public interface ICreateWorkItemsStrategy
{
    IEnumerable<object> CreateWorkItems();
}

public class CreateTypeAStrategy : ICreateWorkItemsStrategy
{
    public CreateTypeAStrategy(TypeA typeA)
    {

    }
    public IEnumerable<object> CreateWorkItems()
    {
        throw new NotImplementedException();
    }
}

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<CreateTypeAStrategy>().Keyed<ICreateWorkItemsStrategy>(typeof(TypeA));
        var container = builder.Build();

        int a_id;
        using (var ctx = new ApplicationDbContext())
        {

            var a = new TypeA { Ref = new RefForProxy() };
            ctx.TypeAs.Add(a);
            ctx.SaveChanges();
            a_id = a.Id;
        }

        using (var ctx = new ApplicationDbContext())
        {
            var aProxy = ctx.TypeAs.SingleOrDefault(x => x.Id == a_id);

            var strategy = container.ResolveKeyed<ICreateWorkItemsStrategy>(aProxy.GetType(), new TypedParameter(aProxy.GetType(), aProxy));
        }
    }
}

Solution

  • ObjectContext.GetObjectType is the method you need.

    Returns the entity type of the POCO entity associated with a proxy object of a specified type.

    It also the return the POCO type if the specified type is not a proxy but the POCO type.

    Type t = ObjectContext.GetObjectType(aProxy.GetType()); 
    var strategy = container.ResolveKeyed<ICreateWorkItemsStrategy>(t, new TypedParameter(t, aProxy));