How to inject and use Serilog (Ilogger) when web-api startup - dependency-injection

I'm developing a .NET core 3.1 Console application (web-api).
I use a Serilog service (it is basically using the Microsoft.Extensions.Logging).
The Serilog is injected and can be used in the FW Controllers methods.
Now - I need something a little bit different - Whenever the system is starting up (after being down) I need to make an http post request - you can see it when executing the ConnectionInitiator.Initiate(), in the startup method. In that same scope (method\class) - I need to use the logger, in order to log some data. Now - If the request would be through the controller - the logger, would be available (by the DI).
To make a long story short - I need somehow to inject the Ilogger to the class or to make it available in some other way. I've tried use the logger in the startUp, but this seems to be impossible (since .net core 3.0 - if I understand correctly)
See my code:
Program.cs:
public class Program
{
public static void Main(string[] args)
{
var loggerConfig = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();
//Reading the appconfig.json
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(loggerConfig).CreateLogger();
try
{
Log.Information("System Started up");
CreateWebHostBuilder(args).Build().Run();
}
catch (Exception ex)
{
Log.Fatal(ex, "THE APPLICATION FAILED TO START UP");
}
finally
{
Log.CloseAndFlush();
}
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args)
{
return WebHost.CreateDefaultBuilder(args).ConfigureLogging((context, logging) =>
{
logging.ClearProviders();
}).UseSerilog().UseStartup<Startup>();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
StartUp.cs
public class Startup
{
public Startup(IConfiguration configuration/*, Microsoft.Extensions.Logging.ILogger logger*/)
{
Configuration = configuration;
ConnectionInitiator.Initiate(configuration/*, logger*/);
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddControllers();
services.AddLogging(loggingBuilder => loggingBuilder.AddSerilog(dispose: true));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().SetIsOriginAllowed((host) => true).AllowCredentials());
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
ConnectionInitiator.cs:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace AAA.BL
{
public static class ConnectionInitiator
{
private static readonly object threadlock = new object();
private static MyConfig myConfig;
private static ILogger ilogger;
/*
public ConnectionInitiator(ILogger _logger)
{
ilogger = _logger;
}
*/
public static void/*async Task*/ Initiate(IConfiguration configuration/*, ILogger ilogger*/)
{
HttpRequester httpRequester = new HttpRequester();
if (myConfig == null)
{
myConfig = new myConfig(configuration);
}
IssueOTPResponse response = /*await*/ httpRequester.PostSomething(myConfig, ilogger).Result; //Double check thread safe singleton implementation
if (response.ststuacode != 200)
{
ilogger.logcritical($"critical error when initiate connection (connectioninitiator): {response.statusdescription}");
}
}
}
}

It seems like the answer is much simpler that I expected - By using the Serilog and was added as a service in the Configure method - It can be reached globally (in every place of the namepsace) by using the static class Log and its static method Logger, for example:
Log.Logger.Information("XXXXX");

Related

C# .NET Core 3.1 Serilog usage in BackgroundService

Following a tutorial on how to use Serilog I read the settings from an appsettings.json file - and all below works well, when things are simple:
Main program (in simple MVP version):
public static void Main(string[] args)
{
//Read Configuration from appSettings
var config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
//Initialize Logger
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(config).CreateLogger();
try
{
Log.Information("Starting up the service");
CreateHostBuilder(args).Build().Run();
....
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseWindowsService()
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
})
.UseSerilog();
Then the class with the BackgroundService:
....
using Microsoft.Extensions.Logging;//and not Serilog!!
public class Worker : BackgroundService
{
private readonly ILogger _logger;
....
public Worker(ILogger<Worker> logger)
{
_logger = logger;
}
---------------------SIMPLE THINGS FOR ME ENDS HERE :-) ----------------------------------
Now, I want to build it up to a "real" program from this first MVP - placing function in seperate classes according to SOLID principles.For instance my first class is a ConfigurationCollector collecting all relevant paramters from the appsettings.json file that I place in a seperat class. The class works and does it jobs - but I want logging to work - and I try to use the allready configured Serilog logger used accross class (just as I did with ILogger, so that the Worker object creates a new ConfigurationCollector class like
public Worker(ILogger<Worker> logger)
{
_logger = logger;
_configCollector = new ConfigCollector(logger);
}
I know that logger is now a type of
ILogger<ConfigCollector>
which is not
ILogger<Worker>
But how do I inject the original Serilog from the initiation of the service into each class used, such that the objects are shown properly in the logs?
public class ConfigCollector
{
private readonly ILogger<ConfigCollector> _logger;
....
public ConfigCollector(ILogger<ConfigCollector> logger)
{
_logger = logger;
}
.NET 6 Background service
.UseSerilog((builder, loggerConfig) =>
loggerConfig.ReadFrom.Configuration(builder.Configuration))
.Build();

ServiceLocator with Autofac in asp.net core 3.1

I'm developing an asp.net core 3.1 webapi application and i'm using Autofac as DI container.
For one particular case i cannot use ConstructorInjection nor propertyinjection nor methodinjection. My only way is to implement a sort of ServiceLocator pattern with the support of Autofac.
*I known that the service locator is an antipattern, but i will use that only if it will be the only chance *
Said that, I create a little static class :
public static class ServiceLocator
{
private static XXXX Resolver;
public static T Resolve<T>()
{
return Resolver.Resolve<T>();
}
public static void SetCurrentResolver(XXXX resolver)
{
Resolver = resolver;
}
}
I write XXXX on the type of Resolver property because i don't know which is the Autofac class to use. The method SetCurrentResolver will be called in the Configure method of Startup.cs
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILifetimeScope serviceProvider)
{
//OTHER STUFF NOT RELATED HERE
ServiceLocator.SetCurrentResolver(serviceProvider);
}
I tried to pass the instance of ILifetimeScope but when i use it later in the service locator it will be Disposed and then not work. I thinked to pass an IContainer object but i'm not able to retrieve an instance in Startup.cs (neither in the Configure method nor in the ConfigureContainer)
I Report the ConfigureContainer method for completion
public void ConfigureContainer(ContainerBuilder builder)
{
//first register the dependency for WebApi Project
builder.RegisterType<HttpContextUserService>().As<IUserService>().SingleInstance();
//and then register the dependency for all other project
var appConfiguration = new AppConfiguration();
Configuration.GetSection("Application").Bind(appConfiguration);
builder.RegisterInstance(appConfiguration).SingleInstance();
builder.RegisterModule(new DependencyInjectionBootstrapper(appConfiguration));
}
Anyone can help me with this problem?
Thanks
This is actually answered in the Autofac docs if you look at the example.
Here are the relevant bits.
public class Startup
{
public Startup(IHostingEnvironment env)
{
// Body omitted for brevity.
}
public ILifetimeScope AutofacContainer { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
// Body omitted for brevity.
}
public void ConfigureContainer(ContainerBuilder builder)
{
// Body omitted for brevity.
}
public void Configure(IApplicationBuilder app)
{
// If, for some reason, you need a reference to the built container, you
// can use the convenience extension method GetAutofacRoot.
// THIS IS WHERE YOU'D SET YOUR SERVICE LOCATOR.
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
}
}

Service Fabric with multiple endpoints and dependency injection

I'm currently working on a POC project and I'm trying to figure out how I can share a service dependency between different endpoints to control application state and handle all service requests (lets call it ControlService) - specifically when one of those endpoints is a KestrelCommunicationListener / HttpSysCommunicationListener and combined with a FabricTransportServiceRemotingListener (or any other type of custom listener)
Autofac looked promising but the examples don't show how to get a HTTP listener working when the container is built in startup rather than the main entry point - would I need to pass the container to MyFabricService so it can be passed into and added to by the startup registrations?
I've seen references to using container.Update() or adding registrations on the fly using container.BeginLifetimeScope() but they are all using a container built in main and then I'm not sure how I would add the APIs created by the HTTP listener to the original container.
I'm possibly not explaining it that well so in summary I'm looking to have something like the below service that can receive communications via n. different endpoints - process the message and then send messages out via n. clients (aka other service endpoints)
Happy to clarify if anything is unclear - perhaps even using another creative diagram :)
Updated:
From Program.Main()
ServiceRuntime.RegisterServiceAsync("ManagementServiceType",
context => new ManagementService(context)).GetAwaiter().GetResult();
Here is my fabric service
public ManagementService(StatefulServiceContext context)
: base(context)
{
//this does not work but is pretty much what I'm after
_managementService = ServiceProviderFactory.ServiceProvider.GetService(typeof(IManagementService)) as IManagementService;
}
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners() =>
new ServiceReplicaListener[]
{
//create external http listener
ServiceReplicaListenerFactory.CreateExternalListener(typeof(Startup), StateManager, (serviceContext, message) => ServiceEventSource.Current.ServiceMessage(serviceContext, message), "ServiceEndpoint"),
//create remoting listener with injected dependency
ServiceReplicaListenerFactory.CreateServiceReplicaListenerFor(() => new RemotingListenerService(_managementService), "ManagmentServiceRemotingEndpoint", "ManagementServiceListener")
};
ServiceReplicaListener
public static ServiceReplicaListener CreateExternalListener(Type startupType, IReliableStateManager stateManager, Action<StatefulServiceContext, string> loggingCallback, string endpointname)
{
return new ServiceReplicaListener(serviceContext =>
{
return new KestrelCommunicationListener(serviceContext, endpointname, (url, listener) =>
{
loggingCallback(serviceContext, $"Starting Kestrel on {url}");
return new WebHostBuilder().UseKestrel()
.ConfigureServices((hostingContext, services) =>
{
services.AddSingleton(serviceContext);
services.AddSingleton(stateManager);
services.AddApplicationInsightsTelemetry(hostingContext.Configuration);
services.AddSingleton<ITelemetryInitializer>((serviceProvider) => new FabricTelemetryInitializer(serviceContext));
})
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddServiceFabricConfiguration(serviceContext);
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddDebug();
})
.UseContentRoot(Directory.GetCurrentDirectory())
.UseServiceFabricIntegration(listener, ServiceFabricIntegrationOptions.None)
.UseStartup(startupType)
.UseUrls(url)
.Build();
});
});
}
Startup
public class Startup
{
private const string apiTitle = "Management Service API";
private const string apiVersion = "v1";
private readonly IConfiguration configuration;
public Startup(IConfiguration configuration)
{
this.configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
var modules = new List<ICompositionModule>
{
new Composition.CompositionModule(),
new BusinessCompositionModule()
};
foreach (var module in modules)
{
module.AddServices(services, configuration);
}
services.AddSwashbuckle(configuration, apiTitle, apiVersion, "ManagementService.xml");
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddApplicationInsights(app.ApplicationServices);
// app.UseAuthentication();
// app.UseSecurityContext();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseCors("CorsPolicy");
app.UseMvc();
app.UseSwagger(apiTitle, apiVersion);
//app.UseMvc(routes =>
//{
// routes.MapRoute(
// name: "default",
// template: "{controller=Home}/{action=Index}/{id?}");
//});
}
}
All the service dependencies are added in the CompositionModules using Microsoft.Extensions.DependencyInjection (not autofac) in startup.cs
This works great and creates my HTTP listener - I now just need a way of getting access to my services that were added to the container during startup of my http listener / webhost.
You can use Autofac.Integration.ServiceFabriŅ, an Autofac extension to support Service Fabric. You need to create a container in Program.cs
var builder = new ContainerBuilder();
builder.RegisterServiceFabricSupport();
builder.RegisterType<SomeService>().As<IManagementService>();
builder.RegisterStatelessService<ManagementService>("ManagementServiceType");
using (builder.Build())
{
// Prevents this host process from terminating so services keep running.
Thread.Sleep(Timeout.Infinite);
}
Then you can inject it to the constructor of your fabric service. You can find more information on this topic on https://alexmg.com/posts/introducing-the-autofac-integration-for-service-fabric
#Tim
Sorry for a late response. Currently I am working on library package that we use in our company for internal projects. This library simplifies configuration of Reliable Services. I think our recent enhancements can do what you need to do (hope I get the use case correctly).
All the information about the library can be found on project page on GitHub and NuGet package can be found here (please note that it is a pre-release version but we are planning to turn into complete release soon).
In case you have any questions or need more information feel free to contact me.
UPDATE
I have create a sample application. Please feel free to try it.
Here is a code example.
public interface IManagementService
{
string GetImportantValue();
}
public interface IMessageProvider
{
string GetMessage();
}
public class MessageProvider : IMessageProvider
{
public string GetMessage()
{
return "Value";
}
}
public class ManagementService : IManagementService
{
private readonly IMessageProvider provider;
public ManagementService(
IMessageProvider provider)
{
this.provider = provider;
}
public string GetImportantValue()
{
// Same instances should have the same hash
return this.provider.GetMessage() + $"Hash: {this.GetHashCode()}";
}
}
public interface IRemotingImplementation : IService
{
Task<string> RemotingGetImportantValue();
}
public class RemotingImplementation : IRemotingImplementation
{
private readonly IManagementService managementService;
public RemotingImplementation(
IManagementService managementService)
{
this.managementService = managementService;
}
public Task<string> RemotingGetImportantValue()
{
return Task.FromResult(this.managementService.GetImportantValue());
}
}
public class WebApiImplementationController : ControllerBase
{
private readonly IManagementService managementService;
public WebApiImplementationController(
IManagementService managementService)
{
this.managementService = managementService;
}
[HttpGet]
public Task<string> WebApiGetImportantValue()
{
return Task.FromResult(this.managementService.GetImportantValue());
}
}
public class WebApiStartup
{
private readonly IConfiguration configuration;
public WebApiStartup(
IConfiguration configuration)
{
this.configuration = configuration;
}
public void ConfigureServices(
IServiceCollection services)
{
services.AddMvc();
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
app.UseMvcWithDefaultRoute();
}
}
internal static class Program
{
/// <summary>
/// This is the entry point of the service host process.
/// </summary>
private static void Main()
{
var host = new HostBuilder()
.ConfigureServices(
services =>
{
services.AddTransient<IMessageProvider, MessageProvider>();
services.AddSingleton<IManagementService, ManagementService>();
})
.ConfigureStatefulService(
serviceBuilder =>
{
serviceBuilder
.UseServiceType("StatefulServiceType")
.DefineAspNetCoreListener(
listenerBuilder =>
{
listenerBuilder
.UseEndpointName("ServiceEndpoint")
.UseKestrel()
.UseUniqueServiceUrlIntegration()
.ConfigureWebHost(
webHostBuilder =>
{
webHostBuilder.UseStartup<WebApiStartup>();
});
})
.DefineRemotingListener(
listenerBuilder =>
{
listenerBuilder
.UseEndpointName("ServiceEndpoint2")
.UseImplementation<RemotingImplementation>();
});
})
.Build()
.Run();
}
}

Calling service/repository methods in ASP.Net Core middleware

ASP.Net Core noob here...I am using an ASP.Net Core WebAPI core project using DNX451 with EF 6.
I have a requirement to implement API Key auth in our service. To do this I have created middleware that gets information from the request and proceeds with authentication. It is SUPPOSED to go to the database, get the key to match, and then return and do the validation.
Here is the middleware implemented to look at the context and get the APIKey
AuthenticationHandler
public class AuthorizationHandler
{
private readonly RequestDelegate _next;
private IAuthenticationService _authenticationService;
public AuthorizationHandler(RequestDelegate next, IAuthenticationService authService)
{
_authenticationService = authService;
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
var apiKey = context.Request.Headers["Key"];
var location = context.Request.Headers["Host"];
var locationKey = _authenticationService.GetApiKey(location);
if (apiKey == locationKey)
await _next(context);
context.Response.StatusCode = 403;
context.Response.Headers.Add("WWW-Authenticate",
new[] { "Basic" });
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.Headers.Add("WWW-Authenticate",
new[] { "Basic" });
}
}
}
Here is the startup class with context and middleware registration
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(k => new DbContext(Configuration["Data:Context:ConnectionString"]));
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseIISPlatformHandler();
app.UseStaticFiles();
app.RegisterAuthorizationHeader();
app.RegisterAuthorization();
app.UseMvc();
}
// Entry point for the application.
public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
Here is Auth service
public interface IAuthenticationService
{
string GetApiKey(string location);
}
public class AuthenticationService: IAuthenticationService
{
private IApiKeyRepository _apiKeyRepository;
public AuthenticationService(IApiKeyRepository repo)
{
_apiKeyRepository= repo;
}
public string GetApiKey(string location)
{
return _apiKeyRepository.GetApiKeyByLocation(location);
}
}
The repo
public interface IApiRepository
{
string GetApiKeyByLocation(string location);
}
public class ApiRepository: IApiRepository
{
private DbContext _context;
public ApiRepository(DbContext context)
{
_context = context;
}
public string GetApiKeyByLocation(string location)
{
var apiRow = _context.ApiKeyStore.FirstOrDefault(a => a.Location == location);
return apiRow == null ? string.Empty : apiRow.APIKey;
}
}
When attempting this I get the following error:
The context cannot be used while the model is being created. This
exception may be thrown if the context is used inside the
OnModelCreating method or if the same context instance is accessed by
multiple threads concurrently. Note that instance members of DbContext
and related classes are not guaranteed to be thread safe.
Now, when I debug this every break point is hit twice. I believe I understand WHY this issue is occurring but have no idea how to fix it.
Can someone give me an idea, please? Any better solution ideas?
To use scoped dependencies in a middleware (which is necessarily a singleton by definition), the best approach is to flow it as a parameter of InvokeAsync instead of flowing it via the constructor:
public async Task Invoke(HttpContext context, IAuthenticationService authenticationService)
{
try
{
var apiKey = context.Request.Headers["Key"];
var location = context.Request.Headers["Host"];
var locationKey = authenticationService.GetApiKey(location);
if (apiKey == locationKey)
await _next(context);
context.Response.StatusCode = 403;
context.Response.Headers.Add("WWW-Authenticate",
new[] { "Basic" });
}
catch (Exception ex)
{
context.Response.StatusCode = 500;
context.Response.Headers.Add("WWW-Authenticate",
new[] { "Basic" });
}
}

ASP.Net Core MVC Dependency Injection not working

I am trying to inject a interface into to my HomeController and I am getting this error:
InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Configuration.IConfiguration' while attempting to activate
My Startup class is as follows:
public Startup(IApplicationEnvironment appEnv)
{
var builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddEnvironmentVariables()
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options => options
.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
services.AddSingleton(provider => Configuration);
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
try
{
using (var serviceScope = app.ApplicationServices
.GetRequiredService<IServiceScopeFactory>()
.CreateScope())
{
serviceScope.ServiceProvider
.GetService<ApplicationDbContext>()
.Database.Migrate();
}
}
catch { }
}
app.UseIISPlatformHandler(options => options.AuthenticationDescriptions.Clear());
app.UseApplicationInsightsExceptionTelemetry();
app.UseStaticFiles();
app.UseIdentity();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.Run((async (context) =>
{
await context.Response.WriteAsync("Error");
}));
}
and my HomeController constructor is:
public HomeController(IConfiguration configuration, IEmailSender mailService)
{
_mailService = mailService;
_to = configuration["emailAddress.Support"];
}
Please tell me where I am mistaken.
Microsoft.Extensions.DependencyInjection.ServiceLookup.Service.PopulateCallSites(ServiceProvider provider, ISet`1 callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
Try injecting it as an IConfigurationRoot instead of IConfiguration:
public HomeController(IConfigurationRoot configuration
, IEmailSender mailService)
{
_mailService = mailService;
_to = configuration["emailAddress.Support"];
}
In this case, the line
services.AddSingleton(provider => Configuration);
is equivalent to
services.AddSingleton<IConfigurationRoot>(provider => Configuration);
because the Configuration property on the class is declared as such, and injection will be done by matching whatever type it was registered as. We can replicate this pretty easily, which might make it clearer:
public interface IParent { }
public interface IChild : IParent { }
public class ConfigurationTester : IChild { }
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
IChild example = new ConfigurationTester();
services.AddSingleton(provider => example);
}
public class HomeController : Controller
{
public HomeController(IParent configuration)
{
// this will blow up
}
}
However
As stephen.vakil mentioned in the comments, it would be better to load your configuration file into a class, and then inject that class into controllers as needed. That would look something like this:
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
You can grab these configurations with the IOptions interface:
public HomeController(IOptions<AppSettings> appSettings)
In Core 2.0 it's recommended to use IConfiguration instead of IConfigurationRoot
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
from https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/#add-configuration-providers
When moving a project from .Net Core 1.x to 2.0, change all IConfigurationRoot to IConfiguration

Resources