unable to inject dependency in .net core 3.1 - c#

Hi i am following microsoft docs ...
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1#json-configuration-provider
in order to inject configurations as singleton in .NET Core Web API
Here is Program.cs code where i load my configurations:
public class Program
{
public static Dictionary<string, string> arrayDict =
new Dictionary<string, string>
{
{"connString", "Data Source =xxx/xxx;User Id =xxx;Password =xxx"}
};
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
builder.AddInMemoryCollection(arrayDict);
builder.AddJsonFile(
"appsettings.json", optional: false, reloadOnChange: false);
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Here in Startup.cs i use following
public class Startup
{
private readonly IConfiguration Configuration;
public Startup(IConfiguration config)
{
Configuration = config;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSingleton<IConfiguration>(Configuration);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Still when i am using dependency injection in my Controller i am unable to inject IConfiguration, and get following error at invoking cotroller action (runtime error):
A suitable constructor for type 'IrisDotNetCore.Controllers.LoginController' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.
LoginController.cs Code:
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
IConfiguration _configuration;
LoginController(IConfiguration configuration)
{
_configuration = configuration;
}
}
What is possibly wrong here?

Your constructor has to be public or internal - remember that in your situation the instance of the LoginController can't be created (because LoginController method is private). Even the error message (Ensure the type is concrete and services are registered for all parameters of a public constructor) suggests this.

Related

How to use startup class inside program file on .NET 6?

I working on an ASP.NET Core 2.2 web application. I have some issues when upgrade my application to .NET 6.
My issue is that there's no startup class in .NET 6.0 and I found program.cs file only.
I add startup class on my web application but I don't know how to use it inside Program.cs.
How to add or use startup class inside my program.cs?
This is the startup.cs file in .NET Core 2.2:
public class Startup
{
private readonly IConfigurationRoot configRoot;
private AppSettings AppSettings { get; set; }
public Startup(IConfiguration configuration)
{
Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
Configuration = configuration;
IConfigurationBuilder builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json");
configRoot = builder.Build();
AppSettings = new AppSettings();
Configuration.Bind(AppSettings);
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddController();
services.AddDbContext(Configuration, configRoot);
services.AddIdentityService(Configuration);
services.AddAutoMapper();
services.AddScopedServices();
services.AddTransientServices();
services.AddSwaggerOpenAPI();
services.AddMailSetting(Configuration);
services.AddServiceLayer();
services.AddVersion();
services.AddHealthCheck(AppSettings, Configuration);
services.AddFeatureManagement();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory log)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(options =>
options.WithOrigins("http://localhost:3000")
.AllowAnyHeader()
.AllowAnyMethod());
app.ConfigureCustomExceptionMiddleware();
log.AddSerilog();
//app.ConfigureHealthCheck();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.ConfigureSwagger();
app.UseHealthChecks("/healthz", new HealthCheckOptions
{
Predicate = _ => true,
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse,
ResultStatusCodes =
{
[HealthStatus.Healthy] = StatusCodes.Status200OK,
[HealthStatus.Degraded] = StatusCodes.Status500InternalServerError,
[HealthStatus.Unhealthy] = StatusCodes.Status503ServiceUnavailable,
},
}).UseHealthChecksUI(setup =>
{
setup.ApiPath = "/healthcheck";
setup.UIPath = "/healthcheck-ui";
//setup.AddCustomStylesheet("Customization/custom.css");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
And this is my .NET 6 program.cs:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
How to use the startup class inside program.cs class ?
Updated Post
every thing is working but configure service not working
because i don't know how to implement ILoggerFactory
on startup
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory log)
{
}
on program.cs
startup.Configure(app, app.Environment,???);
How to add logger factory as third paramter on program.cs
ILoggerFactory is buit in class
Updated it solved using
var app = builder.Build();
startup.Configure(
app,
builder.Environment,
app.Services.GetRequiredService<FooService>(),
app.Services.GetRequiredService<ILoggerFactory>()
);
can you please tell me how to apply swagger ui to check my api
New templates use the so called minimal hosting model but nobody prevents from switching back to the generic hosting one used previously (or via WebHost).
If you want to work with top-level statements you can copy contents of Main method to the Program.cs file and then copy all other methods declared in the old Program class. New Program.cs potentially can look something like this:
await CreateHostBuilder(args)
.Build()
.RunAsync();
// do not forget to copy the rest of the setup if any
static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
Or just remove the Startup class completely and move configure methods to corresponding parts of new file (maybe extracting some to concise extension methods).
You can manually instantiate the Startup and manually call the method ConfigureServices and Configure :
var builder = WebApplication.CreateBuilder(args);
var startup = new Startup(builder.Configuration);
startup.ConfigureServices(builder.Services);
var app = builder.Build();
startup.Configure(app, builder.Environment);
In ASP.NET Core 2.*, Startup.Configure accepted injected service :
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSingleton<IFooService, FooService>();
}
public void Configure(WebApplication app, IWebHostEnvironment env, IFooService fooService, ILoggerFactory loggerFactory)
{
fooService.Init();
...
}
}
Then you can :
var app = builder.Build();
startup.Configure(
app,
builder.Environment,
app.Services.GetRequiredService<FooService>(),
app.Services.GetRequiredService<ILoggerFactory>()
);
When I migrated my APIs, first I consider to reuse the Startup class... but finally I moved the configuration in extension methods.

service AutoMapper can't be resolved

this might be a duplicate of Unable to resolve service for type 'AutoMapper.Mapper' but it's been a year since that was asked and I have a slightly different setup, I think.
I have a .NET 5.0 webapi project, that has a startup class that looks like this
public class Startup
{
private readonly IConfiguration _config;
public Startup(IConfiguration config)
{
_config = config;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddApplicationServices(_config); //This is to keep the Startup class clean
services.AddControllers();
services.AddCors();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "ts.API v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(x => x.AllowAnyHeader().AllowAnyMethod()
.WithOrigins("https://localhost:4200"));
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
I have a separate ApplicationServiceExtension that handles services. This is that class. This is where I call AddAutoMapper. I've tried skipping this and putting it directly into the Startup.cs but that didn't make a difference.
public static class ApplicationServiceExtensions
{
public static IServiceCollection AddApplicationServices(this IServiceCollection services, IConfiguration config)
{
services.AddScoped<IUserRepository, UserRepository>();
services.AddAutoMapper(typeof(AutoMapperProfiles).Assembly);
services.AddDbContext<DataContext>(options =>
{
options.UseSqlServer(config.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly("ts.Data"));
});
return services;
}
}
In a separate project (a console project) I handle everything to do with data coming from the database. This is also where I use a UserRepository.cs that extends IUserRepository. I hold all my DTOs there as well as my AutoMapper Profiles. Basically, I don't even need AutoMapper in my webapi project but I don't know how else to get it running other than adding it to the Startup.cs. Maybe I should mention that I'm pretty new to .NET core/5.0 and haven't really used AutoMapper before let alone set it up from scratch.
The error I'm getting looks like this
Unhandled exception. System.AggregateException: Some services are not able to be constructed
(Error while validating the service descriptor 'ServiceType: ts.Data.Interfaces.IUserRepository Lifetime:
Scoped ImplementationType: ts.Data.Repositories.UserRepository': Unable to resolve service for type 'AutoMapper.Mapper'
while attempting to activate 'ts.Data.Repositories.UserRepository'.)
Just in case you would like to see it, here is my UserRepository.
public class UserRepository : IUserRepository
{
private readonly DataContext _context;
private readonly Mapper _mapper;
public UserRepository(DataContext context, Mapper mapper)
{
_mapper = mapper;
_context = context;
}
public async Task<IEnumerable<UserDto>> GetAllAsync()
{
return await _context.Users
.ProjectTo<UserDto>(_mapper.ConfigurationProvider)
.ToListAsync();
}
}
If anyone has any idea why I'm getting this error, I'd really appreciate the help. I've been stuck with this too long and it's probably something super simple too.
Remove Assembly and try.
services.AddAutoMapper(typeof(AutoMapperProfiles));
At the end of the Startup.cs add following method
private static void RegisterServices(IServiceCollection services, IConfiguration config)
{
ApplicationServiceExtensions.AddApplicationServices(services, config);
}
Call RegisterServices and pass services and _config at end of ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddCors();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "API", Version = "v1" });
});
RegisterServices(services, _config);
}
And make AddApplicationServices void, move AddAutoMapper to the top
public static class ApplicationServiceExtensions
{
public static void AddApplicationServices(IServiceCollection services, IConfiguration config)
{
services.AddAutoMapper(typeof(AutoMapperProfiles));
services.AddScoped<IUserRepository, UserRepository>();
services.AddDbContext<DataContext>(options =>
{
options.UseSqlServer(config.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly("ts.Data"));
});
}
}
Also AutoMapperProfiles should inherit Profile
public class AutoMapperProfiles : Profile
{
public AutoMapperProfiles()
{
CreateMap<Initiative, InitiativeViewModel>();
}
}
Try adding automapper like this:
services.AddAutoMapper(configuration => configuration
.AddProfile<AutoMapperProfiles>(), typeof(Startup));
And inject IMapper instead of Mapper in your UserRepository.

Autofac configuration for ASP.Net Core 3.1 not working

I am trying to use Autofac with ASP.Net Core 3.1 but I am getting an exception which does not make sense.
I am getting the following exception:
Autofac.Core.Activators.Reflection.NoConstructorsFoundException: 'No accessible constructors were found for the type 'Microsoft.AspNetCore.Mvc.ModelBinding.CompositeBindingSource'.'
I think the issue might be because of the order of services registered but I can't figure out what I am doing wrong. My configuration is as follows:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
Startup.cs class
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public ILifetimeScope AutofacContainer { get; private set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<EShopDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DBConnection")));
services.AddSwaggerGen();
services.AddOptions();
}
public void ConfigureContainer(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterModule(new AutofacModule());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
this.AutofacContainer = app.ApplicationServices.GetAutofacRoot();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "eShop");
c.RoutePrefix = string.Empty;
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
AutofacModule.cs class
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// scan all assemblies in current application domain and resolve them on convention
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsImplementedInterfaces();
}
}
What am I missing?
I was able to find the problem with the help of examples code...
The problem for me was in the AutofacModule.cs class. I was scanning the assembly incorrectly. Here is the working code.
public class AutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
// scan all assemblies in current application domain and resolve them on convention
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.AsImplementedInterfaces();
}
}
Autofac has examples of projects in Github and I found out that their documentation was different from their example code. This is the link of the ASP.Net Core 3.1 Example. for anyone who wants to see the configuration.

ASP.NET Core 3.1 Logging at Startup [duplicate]

In order to debug a .NET Core app which is failing on startup, I would like to write logs from within the startup.cs file. I have logging setup within the file that can be used in the rest of the app outside the startup.cs file, but not sure how to write logs from within the startup.cs file itself.
.Net Core 3.1
Unfortunately, for ASP.NET Core 3.0, the situation is again a bit different. The default templates use the HostBuilder (instead of the WebHostBuilder) which sets up a new generic host that can host several different applications, not limited to web applications. Part of this new host is also the removal of the second dependency injection container that previously existed for the web host. This ultimately means that you won’t be able to inject any dependencies apart from the IConfiguration into the Startup class. So you won’t be able to log during the ConfigureServices method. You can, however, inject the logger into the Configure method and log there:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger)
{
logger.LogInformation("Configure called");
// …
}
If you absolutely need to log within ConfigureServices, then you can continue to use the WebHostBuilder which will create the legacy WebHost that can inject the logger into the Startup class. Note that it’s likely that the web host will be removed at some point in the future. So you should try to find a solution that works for you without having to log within ConfigureServices.
.NET Core 2.x
This has changed significantly with the release of ASP.NET Core 2.0. In ASP.NET Core 2.x, logging is created at the host builder. This means that logging is available through DI by default and can be injected into the Startup class:
public class Startup
{
private readonly ILogger<Startup> _logger;
public IConfiguration Configuration { get; }
public Startup(ILogger<Startup> logger, IConfiguration configuration)
{
_logger = logger;
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogInformation("ConfigureServices called");
// …
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
_logger.LogInformation("Configure called");
// …
}
}
Option 1: Directly use log (e.g. Serilog) in startup-
public class Startup
{
public Startup(IHostingEnvironment env)
{
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.WriteTo.RollingFile(Path.Combine(env.ContentRootPath, "Serilog-{Date}.txt"))
.CreateLogger();
Log.Information("Inside Startup ctor");
....
}
public void ConfigureServices(IServiceCollection services)
{
Log.Information("ConfigureServices");
....
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
Log.Information("Configure");
....
}
Output:
To setup Serilog in asp.net-core application, check out the Serilog.AspNetCore package on GitHub.
Option2: Configure logging in program.cs like this-
var host = new WebHostBuilder()
.UseKestrel()
.ConfigureServices(s => {
s.AddSingleton<IFormatter, LowercaseFormatter>();
})
.ConfigureLogging(f => f.AddConsole(LogLevel.Debug))
.UseStartup<Startup>()
.Build();
host.Run();
User loggerFactory in startup like this-
public class Startup
{
ILogger _logger;
IFormatter _formatter;
public Startup(ILoggerFactory loggerFactory, IFormatter formatter)
{
_logger = loggerFactory.CreateLogger<Startup>();
_formatter = formatter;
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogDebug($"Total Services Initially: {services.Count}");
// register services
//services.AddSingleton<IFoo, Foo>();
}
public void Configure(IApplicationBuilder app, IFormatter formatter)
{
// note: can request IFormatter here as well as via constructor
_logger.LogDebug("Configure() started...");
app.Run(async (context) => await context.Response.WriteAsync(_formatter.Format("Hi!")));
_logger.LogDebug("Configure() complete.");
}
}
Complete details available on this link
In .NET Core 3.1, you can create a logger directly using LogFactory.
var loggerFactory = LoggerFactory.Create(builder =>
{
builder.AddConsole();
});
ILogger logger = loggerFactory.CreateLogger<Startup>();
logger.LogInformation("Example log message");
The official solution is currently to setup a local LoggerFactory like this:
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Information);
builder.AddConsole();
builder.AddEventSourceLogger();
});
var logger = loggerFactory.CreateLogger("Startup");
logger.LogInformation("Hello World");
See also: https://github.com/dotnet/aspnetcore/issues/9337#issuecomment-539859667
For .Net 6
var builder = WebApplication.CreateBuilder(args);
...
var app = builder.Build();
var logger = ((IApplicationBuilder)app).ApplicationServices.GetService<ILogger<Program>>();
logger.LogInformation("Some logs");
Or even more easy way:
var builder = WebApplication.CreateBuilder(args);
...
var app = builder.Build();
ILogger logger = app.Logger;
Using Rolf's answer, I put this in my Startup constructor:
private readonly ILogger _logger;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
using var loggerFactory = LoggerFactory.Create(builder =>
{
builder.SetMinimumLevel(LogLevel.Information);
builder.AddConsole();
builder.AddEventSourceLogger();
});
_logger = loggerFactory.CreateLogger<Startup>();
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogInformation("ConfigureServices...");
// ...and so on...
}
For .NET Core 3.0 the official docs has this to say: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-3.0#create-logs-in-startup
Writing logs before completion of the DI container setup in the Startup.ConfigureServices method is not supported:
Logger injection into the Startup constructor is not supported.
Logger injection into the Startup.ConfigureServices method signature is not supported
But as they say in the docs you can configure a service that depends on ILogger, so if you wrote a class StartupLogger:
public class StartupLogger
{
private readonly ILogger _logger;
public StartupLogger(ILogger<StartupLogger> logger)
{
_logger = logger;
}
public void Log(string message)
{
_logger.LogInformation(message);
}
}
Then in Startup.ConfigureServices add the service, then you need to build the service provider to get access to the DI container:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(provider =>
{
var service = provider.GetRequiredService<ILogger<StartupLogger>>();
return new StartupLogger(service);
});
var logger = services.BuildServiceProvider().GetRequiredService<StartupLogger>();
logger.Log("Startup.ConfigureServices called");
}
Edit: this produces a compiler warning, for the sake of debugging your StartUp class this should be OK but not for production:
Startup.cs(39, 32): [ASP0000] Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'.
None of the existing answers worked for me. I'm using NLog, and even building a new ServiceCollection, calling .CreateBuilder() on any service collection, creating a logging service ... none of that would write to a log file during ConfigureServices.
The problem is that logging isn't really a thing until after the ServiceCollection is built, and it's not built during ConfigureServices.
Basically, I just want (need) to log what's going on during startup in a configuration extension method, because the only tier I'm having a problem on is PROD, where I can't attach a debugger.
The solution that worked for me was using the old .NET Framework NLog method:
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
Added that right to the extension method class, and I was able to write to a log ("the" log) during ConfigureServices and after.
I have no idea if this is a good idea to actually release into production code (I don't know if the .NET controlled ILogger and this NLog.ILogger will conflict at any point), but I only needed it to see what was going on.
I use a solution avoiding 3rd party loggers implementing a "logger buffer" with ILogger interface.
public class LoggerBuffered : ILogger
{
class Entry
{
public LogLevel _logLevel;
public EventId _eventId;
public string _message;
}
LogLevel _minLogLevel;
List<Entry> _buffer;
public LoggerBuffered(LogLevel minLogLevel)
{
_minLogLevel = minLogLevel;
_buffer = new List<Entry>();
}
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel >= _minLogLevel;
}
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
{
if (IsEnabled(logLevel)) {
var str = formatter(state, exception);
_buffer.Add(new Entry { _logLevel = logLevel, _eventId = eventId, _message = str });
}
}
public void CopyToLogger (ILogger logger)
{
foreach (var entry in _buffer)
{
logger.Log(entry._logLevel, entry._eventId, entry._message);
}
_buffer.Clear();
}
}
Usage in startup.cs is easy, of course you get log output after call of Configure. But better than nothing. :
public class Startup
{
ILogger _logger;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
_logger = new LoggerBuffered(LogLevel.Debug);
_logger.LogInformation($"Create Startup {env.ApplicationName} - {env.EnvironmentName}");
}
public void ConfigureServices(IServiceCollection services)
{
_logger.LogInformation("ConfigureServices");
services.AddControllersWithViews();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILogger<Startup> logger)
{
(_logger as LoggerBuffered).CopyToLogger(logger);
_logger = logger; // Replace buffered by "real" logger
_logger.LogInformation("Configure");
if (env.IsDevelopment())
Main code:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
}
CreateDefaultBuilder sets up a default console logger.
... configures the ILoggerFactory to log to the console and debug output
Startup code:
using Microsoft.Extensions.Logging;
...
public class Startup
{
private readonly ILogger _logger;
public Startup(IConfiguration configuration, ILoggerFactory logFactory)
{
_logger = logFactory.CreateLogger<Startup>();
Configuration = configuration;
}
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)
{
_logger.LogInformation("hello stackoverflow");
}
I couldn't get the injection of an ILogger to work, but perhaps that's because it's not a controller. More info welcome!
Refs:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1&tabs=aspnetcore2x
Are you making decisions about which services you are using at runtime that you wish to log? Or are you making decisions about how those services are configured, which you wish to log?
In other words;
public void ConfigureServices(IServiceCollection services){
// Do you really want to log something here?
services.AddRazorPages(options => {
// Or would you be satisfied by logging something here?
});
}
If it is only the latter, you can move the implementation of these lambda functions into an IConfigureOptions<T> service, allowing you to inject other services. Continuing the above example, you could create the following;
public class ConfigureRazorPagesOptions : IConfigureOptions<RazorPagesOptions>
{
private readonly ILogger<ConfigureRazorPagesOptions> logger;
public ConfigureRazorPagesOptions(ILogger<ConfigureRazorPagesOptions> logger)
{
this.logger = logger;
}
public void Configure(RazorPagesOptions options)
{
logger.LogInformation("Now I can log here!");
}
}
public void ConfigureServices(IServiceCollection services){
services.AddRazorPages();
services.AddSingleton<IConfigureOptions<RazorPagesOptions>, ConfigureRazorPagesOptions>();
}
If your .ConfigureServices method is getting too complicated, you might want to create such services. However, that's a lot of boilerplate to add for each options type. There is also an equivalent shorthand, to inject other services into a configuration lamda;
services.AddOptions<RazorPagesOptions>()
.Configure<ILogger<RazorPagesOptions>>((options, logger) => {
logger.LogInformation("I can log here too!");
});
This worked for me
private static readonly Logger logger = LogManager.GetLogger("Audit")
I found a very easy implementation:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
var conn = Configuration.GetValue("conn", Configuration.GetConnectionString("Conn"));
Console.WriteLine($#"System starting at {DateTime.Now}");
Console.WriteLine($#"Database: {conn}");
}
Just using Console.WriteLine worked, even on Docker.
Just use the line below for logging in Startup.cs
Log.Information("App started.");

How can "IConfiguration object is registered with DI by default" in Startup.cs in .NET Core 2

In, aspnet core 2, when we want to to Access configuration during startup, we can do it thanks to dependency injection as far as I understood.
For this code in below, how can we pass IConfiguration object to this class with benefits of Dependency Injection ;
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
I saw a sentence:
" The IConfiguration object is registered with DI by default."
How can we succeed this?
In program.cs there is a code like this, do we set IConfiguration object in startup.cs class with this code below? I thought .UseStartup()
code carries out this job(passing IConfiguration object to Startup class) for us. But how?
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(SetupConfiguration)
.UseStartup<Startup>();
private static void SetupConfiguration(WebHostBuilderContext ctx, IConfigurationBuilder builder)
{
//Remove the default configuration options
builder.Sources.Clear();
builder.AddJsonFile("config.json", false, true).
AddEnvironmentVariables();
}
}
I would be so happy if someone can explain this with deep details.
The dependency injection is handled internally for you for the IConfiguration instance. The technical details are easy to find if you browse around the source code. In this case, there is a helper class that mimics a basic DI container, you can see this here.

Categories