Skip to content

Unable to override a named registration in Lamar #343

@torfig

Description

@torfig

I'm using Lamar for DI and the IHostBuilder.OverrideServices method to introduce fakes/mocks during integration testing which works fine until I want to replace a named instance.

builder.OverrideServices(services =>
{
    services.For<IUserController>().Use(Mocks.UserController.Object);
    services.For<ICompanyRepositoryProvider>().Use(Mocks.CompanyRepositoryProvider.Object);
    services.For<IGeoCodingDataAccess>().Use(Mocks.GeoCodingDataAccess.Object);
    services.For<IDbRepository().Use(Mocks.DataAccessRepository.Object).Named("AlreadyRegisteredName");
});

As soon as I add a named instance in OverrideServices that is already registered elsewhere, I get the following error:

System.InvalidOperationException
      HResult=0x80131509
      Message=Referenced instance of Company.DbRepository.Interfaces.IDbRepository named 'AlreadyRegisteredName' does not exist
      Source=Lamar
      StackTrace:
       at Lamar.IoC.Instances.ReferencedInstance.<createPlan>d__10.MoveNext()
       at System.Linq.Enumerable.Any[TSource](IEnumerable`1 source, Func`2 predicate)
       at Lamar.IoC.Instances.Instance.CreatePlan(ServiceGraph services)
       at Lamar.IoC.Instances.ConstructorInstance.buildOutConstructorArguments(ServiceGraph services)
       at Lamar.IoC.Instances.ConstructorInstance.createPlan(ServiceGraph services)
       at Lamar.IoC.Instances.Instance.CreatePlan(ServiceGraph services)
       at Lamar.IoC.Instances.ConstructorInstance.buildOutConstructorArguments(ServiceGraph services)
       at Lamar.IoC.Instances.ConstructorInstance.createPlan(ServiceGraph services)
       at Lamar.IoC.Instances.Instance.CreatePlan(ServiceGraph services)
       at Lamar.IoC.Instances.ConstructorInstance.buildOutConstructorArguments(ServiceGraph services)
       at Lamar.IoC.Instances.ConstructorInstance.createPlan(ServiceGraph services)
       at Lamar.IoC.Instances.Instance.CreatePlan(ServiceGraph services)
       at Lamar.ServiceGraph.planResolutionStrategies()
       at Lamar.ServiceGraph.buildOutMissingResolvers()
       at LamarCodeGeneration.Util.PerfTimer.Record(String text, Action action)
       at Lamar.ServiceGraph.Initialize(PerfTimer timer)
       at Lamar.IoC.Scope..ctor(IServiceCollection services, PerfTimer timer)
       at Lamar.Container..ctor(IServiceCollection services)
       at Lamar.Microsoft.DependencyInjection.LamarServiceProviderFactory.CreateServiceProvider(IServiceCollection containerBuilder)
       at Microsoft.Extensions.Hosting.Internal.ServiceFactoryAdapter`1.CreateServiceProvider(Object containerBuilder)
       at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
       at Microsoft.Extensions.Hosting.HostBuilder.Build()
       at Company.Integration.Orchestrator.IntegrationsOrc.Program.Main(String[] args) in C:\Repos\integration-orc-service\Clients\IntegrationsOrc\Program.cs:line 64

I'm unsure if this has any relevance, but we're using a policy to reference the correct registered name when resolving the IDbRepository (and use an Attribute on the IDbRepository parameter to specify the name to resolve to)

 public class NamedInstancePolicy<T> : ConfiguredInstancePolicy
 {
     /// <inheritdoc/>
     protected override void apply(IConfiguredInstance instance)
     {
         foreach (var param in instance.ImplementationType.GetConstructors()
                                                                  .SelectMany(x => x.GetParameters())
                                                                  .Where(x => x.ParameterType == typeof(T)))
         {
             // Primary route is to resolve the instance based on a custom attribute
             var ipAttribute = param.GetCustomAttribute<InstancePolicyNameAttribute>();
             if (ipAttribute == null)
             {
                 // The IDbConnection parameter was not marked with the correct attribute
                 throw new InvalidOperationException($"A {param.ParameterType.Name} parameter in {instance.Name} does not contain the required InstancePolicyNameAttribute to define which instance should be resolved.");
             }

             // Parameter was correctly set up, assign the named instance to the constructor parameter
             instance.Ctor<T>(param.Name).IsNamedInstance(ipAttribute.InstanceName);
         }
     }
 }

I'm using the latest version of Lamar (8.0.1) and asp.net core 6.0.

This same error occurs if I register the same type with the same name twice. Any ideas how to resolve this? Maybe I could remove the previous named registration somehow (I'd need a way to do that within the OverrideServices method)?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions