I am using Simple Injector to register a concrete type in the container in a .NET Core console app (in Program.cs
), but Simple Injector throws an exception on start up:
The constructor of type Application contains the parameter with name 'configUpdater' and type ConfigUpdater, but ConfigUpdater is not registered. For ConfigUpdater to be resolved, it must be registered in the container. An implicit registration could not be made because Container.Options.ResolveUnregisteredConcreteTypes is set to 'false', which is now the default setting in v5. This disallows the container to construct this unregistered concrete type. For more information on why resolving unregistered concrete types is now disallowed by default, and what possible fixes you can apply, see https://simpleinjector.org/ructd
EDIT: Adding a MRE example which throws the exception:
using System.Threading.Tasks;
using NLog;
using SimpleInjector;
namespace MRE
{
public static class Program
{
private static Container container;
static Program()
{
container = new Container();
container.Register<IApplication, Application>(Lifestyle.Singleton);
var appSettings = new AppSettings();
container.Register(
typeof(AppSettings),
() => appSettings,
Lifestyle.Singleton
);
container.RegisterConditional(
typeof(ILog),
typeCtx => typeof(NLogProxy<>).MakeGenericType(typeCtx.Consumer.ImplementationType),
Lifestyle.Singleton,
predCtx => true
);
container.Register<IConfigUpdater, ConfigUpdater>(Lifestyle.Scoped);
}
public static void Main(string[] args)
{
var application = container.GetInstance<IApplication>();
application.RunAsync();
}
}
public class AppSettings
{
public string ConnectionString { get; set; } = "DataSource=data.db";
}
public interface ILog
{
void Info(string message);
}
public class NLogProxy<T> : ILog
{
private static readonly NLog.ILogger Logger = LogManager.GetLogger(typeof(T).FullName);
public void Info(string message) => Logger.Log(LogLevel.Info, message);
}
public interface IApplication
{
Task RunAsync();
}
public class Application : IApplication
{
private readonly ILog logger;
private readonly IConfigUpdater configUpdater;
public Application(
ILog logger,
IConfigUpdater configUpdater
)
{
this.logger = logger;
this.configUpdater = configUpdater;
}
public Task RunAsync()
{
logger.Info("Running");
configUpdater.DoTask();
return Task.CompletedTask;
}
}
public interface IConfigUpdater
{
Task DoTask();
}
public class ConfigUpdater : IConfigUpdater
{
private readonly AppSettings appSettings;
private readonly ILog logger;
public ConfigUpdater(
AppSettings appSettings,
ILog logger
)
{
this.appSettings = appSettings;
this.logger = logger;
}
public Task DoTask()
{
var connectionString = appSettings.ConnectionString;
logger.Info(connectionString);
return Task.CompletedTask;
}
}
}
EDIT #2:
With the help of the MRE, I discovered my issue was actually hiding behind the scenes. It was a issue with using Lifestyle.Scoped
which for some reason was not the first exception thrown. Setting the default lifestyle to AsyncScopedLifestyle
fixes it.
With the help of the MRE, I found that the actual error was to do with the default Lifestyle
SimpleInjector was using. Adding the line:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
fixes the issue of this question.
As to why the Lifestyle exception wasn't thrown first, I don't know.