JasperFx / lamar

Fast Inversion of Control Tool and Successor to StructureMap
https://jasperfx.github.io/lamar
MIT License
563 stars 118 forks source link

Lamar not Resolving some of my Registered Generic<T> Interface Properties #349

Closed PrisonerZERO closed 1 year ago

PrisonerZERO commented 1 year ago

I have a (vanilla) Generic Repository class that also contains a Generic Interface Property.

Each Generic Repository within the UnitOfWork resolves...but Lamar seems to ignore the Interface Property embedded within the repository class.

All types are registered, so it "should" resolve within each one...but doesn't.

All types are registered, so it "should" resolve within each one...but doesn't.

    var container= IoC.Initialize();
    var unitOfWork = container.GetInstance<WorkflowComponentUnitOfWork>();

    Assert.IsNotNull(unitOfWork.ContextType.AuditResolver); //<-- fails

THE CODE:
Some code excluded for brevity...

    // ServiceRegistry
    public class ContainerRegistry : ServiceRegistry
    {
        public ContainerRegistry()
        {
            Scan(scan =>
            {
                scan.TheCallingAssembly();
                scan.WithDefaultConventions();
                scan.LookForRegistries();
                scan.SingleImplementationsOfInterface();
                //scan.Assembly("Bushido.Framework"); //<-- Tried these...doesn't work
                        //scan.Assembly("Bushido.Framework.Data.Entity"); //<-- ...
                        //scan.Assembly("Bushido.Framework.Data.EntityFrameworkCore"); //<-- ...
                        //scan.Assembly("Bushido.Framework.Security.Principal"); //<-- ...
                //scan.ConnectImplementationsToTypesClosing(typeof(IAuditResolverOf<>)); //<-- Doesn't work
                //scan.AddAllTypesOf(typeof(IAuditResolverOf<>)); //<-- Doesn't work
                //scan.RegisterConcreteTypesAgainstTheFirstInterface();  //<-- Doesn't work
            });

            // --------
            // DATABASE
            For<DbContext>().Use<WorkflowComponentDbContext>();
            For(typeof(IAuditResolverOf<>)).Use(typeof(StandardUserNameAuditResolver<>));
            For(typeof(IAuditableRepository<>)).Use(typeof(GenericAuditableRepository<>));
            For(typeof(IWindowsIdentityHelper)).Use(typeof(WindowsIdentityHelper));

            // Concretes
            ForConcreteType<WorkflowComponentUnitOfWork>().Configure.Setter<DbContext>().Is<WorkflowComponentDbContext>();

            // Policies
            Policies.Add<GenericAuditableRepositoryConfiguredInstancePolicy>(); //<-- Applies concrete DbContext into CTOR dynamically
        }
    }

    // UnitOfWork
    public class WorkflowComponentUnitOfWork : IUnitOfWork
    {
        [SetterProperty]
        public IAuditableRepository<ContextType> ContextType { get; set; }

        [SetterProperty]
        public IAuditableRepository<ObjectState> ObjectState { get; set; }

        [SetterProperty]
        public IAuditableRepository<ObjectStateEvent> ObjectStateEvent { get; set; }

        [SetterProperty]
        public IAuditableRepository<Workflow> Workflow { get; set; }

        [SetterProperty]
        public IAuditableRepository<WorkflowEvent> WorkflowEvent { get; set; }

        [SetterProperty]
        public IAuditableRepository<WorkflowTransition> WorkflowTransition { get; set; }

        // Other code excluded for brevity
    }

    // Repository
    public class GenericAuditableRepository<TEntity> : IAuditableRepository<TEntity> where TEntity : class
    {
        protected DbSet<TEntity> _dbSet;
        protected DbContext _dbContext;

        public GenericAuditableRepository(DbContext dbContext)
        {
           _dbContext = dbContext;
           _dbSet = _dbContext.Set<TEntity>();
        }

        public IAuditResolverOf<TEntity> AuditResolver { get; set; } //<-- Always resolves to NULL

        // Other code excluded for brevity
    }

    // AuditResolver
    public class StandardUserNameAuditResolver<TEntity> : IAuditResolverOf<TEntity>
    {
        // Temporarily added to see if Lamar even tries instantiating it.
        public StandardUserNameAuditResolver()
        {
             // DEBUG: Never hits here
        } 

        public IWindowsIdentityHelper IdentityHelper { get; set; } //<-- Non-Generic: I won't know if this gets recognized until the Resolver is recognized

        // Other code excluded for brevity
    }

LAMAR CONFIGURATION REPORT:
Built by calling WhatDoIHave(). As you can see it understands what IAuditResolverOf<> maps to.

=============================================================================================================================================================================================
    ServiceType                                                     Namespace                                        Lifecycle     Description                                                   
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    DbContext                                                       Microsoft.EntityFrameworkCore                    Transient     new WorkflowComponentDbContext(options)                       
                                                                                                                     Transient     new WorkflowComponentDbContext(options)                       
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    DbContextOptions<WorkflowComponentDbContext>                    Microsoft.EntityFrameworkCore                    Transient     new DbContextOptions<WorkflowComponentDbContext>()            
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<>                                          Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<>()                            
                                                                                                                     Transient     new GenericAuditableRepository<>()                            
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<ContextType>                               Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<ContextType>(dbContext)        
                                                                                                                     Transient     new GenericAuditableRepository<ContextType>(dbContext)        
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<ObjectState>                               Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<ObjectState>(dbContext)        
                                                                                                                     Transient     new GenericAuditableRepository<ObjectState>(dbContext)        
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<ObjectStateEvent>                          Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<ObjectStateEvent>(dbContext)   
                                                                                                                     Transient     new GenericAuditableRepository<ObjectStateEvent>(dbContext)   
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<Workflow>                                  Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<Workflow>(dbContext)           
                                                                                                                     Transient     new GenericAuditableRepository<Workflow>(dbContext)           
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<WorkflowEvent>                             Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<WorkflowEvent>(dbContext)      
                                                                                                                     Transient     new GenericAuditableRepository<WorkflowEvent>(dbContext)      
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditableRepository<WorkflowTransition>                        Bushido.Framework.Data.Entity                    Transient     new GenericAuditableRepository<WorkflowTransition>(dbContext) 
                                                                                                                     Transient     new GenericAuditableRepository<WorkflowTransition>(dbContext) 
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IAuditResolverOf<>                                              Bushido.Framework.Data.Entity.Resolvers          Transient     new StandardUserNameAuditResolver<>()                         
                                                                                                                     Transient     new StandardUserNameAuditResolver<>()                         
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IContainer                                                      Lamar                                            Scoped        Current IContainer                                            
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IServiceContext                                                 Lamar                                            Scoped        Current IServiceContext                                       
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IServiceProvider                                                System                                           Scoped        Current IServiceProvider                                      
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IServiceScopeFactory                                            Microsoft.Extensions.DependencyInjection         Singleton     Current IServiceScopeFactory                                  
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    IWindowsIdentityHelper                                          Bushido.Framework.Security.Principal.Helpers     Transient     new WindowsIdentityHelper()                                   
                                                                                                                     Transient     new WindowsIdentityHelper()                                   
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    Scope                                                           Lamar.IoC                                        Scoped        Current Scope                                                 
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
PrisonerZERO commented 1 year ago

UPDATES: I can resolve the types by-hand in a separate unit test, so Lamar does seem to understand the classes exist...

var resolver = container.GetInstance<IAuditResolverOf<ContextType>>();
var helper = container.GetInstance<IWindowsIdentityHelper>();

So, it seems that the problem is Lamar doesn't recognize the registration of Generic<T> as "Interface Properties".

Thanks for any help...

POST SCRIPT: The link to Generic Types on the Auto-Registration and Conventions page is 404