-
-
Notifications
You must be signed in to change notification settings - Fork 119
Description
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)?