I have a small .net 5 WebApi app, using DryIoc. I am now trying to set up an xUnit test suite for this app, but the integration tests fail immediately because one of the registrations has multiple constructors, even though I am using the same rules for both containers and running the same registrations in the same order as the app.
The registration works fine for the app because the container has ConstructorWithResolvableArguments
set for the factory method, but it's not being set from anywhere in our code. I know I can easily just add that rule to the container for the tests, but I don't understand why a container set up in the exact same way appears to have different rules, and I am concerned there may be other differences that could affect the tests.
In the app, the container is set up like so:
Program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new DryIocServiceProviderFactory(Startup.CreateContainer()))
.ConfigureWebHostDefaults(...);
StartUp.cs
...
public static IContainer CreateContainer() => new Container(DiConfiguration.SetRules);
public void ConfigureContainer(IContainer container)
{
container.RegisterCoreDependencies();
// Site specific registrations
container.ConfigureDomain();
}
DiConfiguration.cs
public static class DiConfiguration
{
public static Rules SetRules(Rules rules)
{
rules = rules.WithAutoConcreteTypeResolution();
rules = rules.WithVariantGenericTypesInResolve();
return rules;
}
public static void RegisterCoreDependencies(this IContainer container)
{
// dependency registrations, not much to see here, nothing clever
// just basic registrations e.g.
container.Register<IFoo, Foo>();
}
In the test suite I am setting up the container like so:
public class Test
{
private object _sut;
public Test()
{
var container = new Container(DiConfiguration.SetRules); // <--- Same rules as the app
container.RegisterCoreDependencies(); // <--- fails here
container.ConfigureDomain();
_sut = container.Resolve<Bar>();
}
[Fact]
public void Some_Test_Here()
{
...
}
}
As you can see, all the container registration code is abstracted out into a shared library (the DiConfiguration
class). The test is failing calling RegisterCoreDependencies
. I don't understand why the rules are different between the two scenarios, is it perhaps something introduced by the DryIocServiceProviderFactory
call in the app setting some extra defaults? (DryIocServiceProviderFactory
is part of the DryIoc.Microsoft.DependencyInjection
package)
The DryIocServiceProviderFactory
will override the existing container rules to conform to MS.DI container. Here is the code: https://github.com/dadhi/DryIoc/blob/5e3f1f7edfe237f69ba33c9166d17e284ca4781a/src/DryIoc.Microsoft.DependencyInjection/DryIocAdapter.cs#L97
Here how the rules are overriden in detail:
private static Rules WithMicrosoftDependencyInjectionRules(Rules rules)
{
rules = rules.Clone(cloneMade: true);
rules._settings |= Settings.TrackingDisposableTransients;
rules._settings &= ~Settings.ThrowOnRegisteringDisposableTransient;
rules._settings &= ~Settings.VariantGenericTypesInResolvedCollection;
rules._factorySelector = SelectLastRegisteredFactory;
rules._made._factoryMethod = DryIoc.FactoryMethod.ConstructorWithResolvableArguments;
return rules;
}