Pass configuration to IHostedService - c#

I'm trying to add a configuration value to an IHostedService but do not know how.
This is what I have at the moment:
Startup
services.Configure<MyOptions>(Configuration.GetSection("MyOptions"));
services.AddHostedService<MyHostedService>();
MyOptions
public class MyOptions
{
public string MyOption{ get; set; }
}
Appsettings
"MyOptions": {
"MyOption": "42"
}
MyHostedService
public MyHostedService(ILogger<MyHostedService> logger)
{
_logger = logger;
// Where are my options?! :(
}

You are almost there. You got only one thing left to do:
Just use constructor dependency injection with IOptions<MyOptions> or related (depending on your scenario) in your IHostedService:
IOptions<TOptions>
IOptionsMonitor<TOptions>
IOptionsSnapshot<TOptions>
public MyHostedService(ILogger<MyHostedService> logger, IOptions<MyOptions> optionsAccessor)
{
_logger = logger;
_options = optionsAccessor.Value;
}
For more details, see Options pattern in ASP.NET Core.

Related

How to Resolve ILogger in Autofac container

I am trying to replace dryIOC container with autofac container for some reason but I don't know the exact syntax how could I resolve ILogger uisng autofac
Here is how I register ILogger in DryIoc
public void Load(IContainer container)
{
container.Register<ILoggerFactory, Log4NetLoggerFactory>();
ConfigureLogger(container);
}
[Localizable(false)]
private void ConfigureLogger(IContainer container)
{
container.Register<ILogger>(
made: Made.Of(
r => typeof(ILoggerFactory).GetMethod(nameof(ILoggerFactory.Create), new[] { typeof(Type) }),
factoryInfo: ServiceInfo.Of<ILoggerFactory>(),
parameters: Parameters.Of.Name("type", r => r.Parent?.ImplementationType ?? typeof(Startup))),
reuse: Reuse.Transient);
}
I have tried something like this, but it does not work with Autofac
container.Register<ILoggerFactory, Log4NetLoggerFactory>();
If you try to resolve an instance of Microsoft.Extensions.Logging.ILogger then you have two options:
Option #1 - Resolve a ILogger<TCategoryName>.
public class Something
{
private readonly ILogger logger;
public Something(ILogger<Something> logger)
{
this.logger = logger;
}
}
Option #2 - Resolve an ILogger instead of ILogger<TCategoryName> automatically.
My nuget package does exactly this using Autofac:
EgonsoftHU.Extensions.Logging.Autofac
It contains an Autofac module. Register it then magic will happen.
public class Something
{
private readonly ILogger logger;
public Something(ILogger logger)
{
this.logger = logger; // It will be an instance of ILogger<Something>.
}
}

Problem injecting repository into ApplicationUser:IdentityUser [duplicate]

Using Asp.Net Core we can make use of Dependency Injection in controllers/repositories.
However, I wish do do some logging in my Entity Class.
class Person
{
private ILogger<Person> _logger;
private List<Pets> pets;
public Person(ILogger<Person> logger)
{
_logger = logger;
}
public bool HasCat()
{
_logger.LogTrace("Checking to see if person has a cat.");
// logic to determine cat ownership
hasCat = true;
return hasCat;
}
}
When the Person class is instantiated by EntityFramework it does not attempt to inject any dependencies.
Can I force this? Am i going about it in completely the wrong way?
Ultimatley I just want to be able to use logging consistently throughout the application.
Thanks,
It is possible but I don't recommend it because I agree with commenters that logging belongs in your services and controllers.
EF Core 2.1 allows injecting the DbContext into a private constructor that EF will invoke. See the official docs.
First you need to expose a LoggerFactory property in your DbContext class.
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options, ILoggerFactory loggerFactory = null)
{
LoggerFactory = loggerFactory;
}
public ILoggerFactory LoggerFactory { get; }
}
Then you can inject the DbContext into a private constructor in your entity class.
public class Person
{
private readonly ILogger _logger;
public Person() { } // normal public constructor
private Person(MyDbContext db) // private constructor that EF will invoke
{
_logger = db.LoggerFactory?.CreateLogger<Person>();
}
public bool HasCat()
{
_logger?.LogTrace("Check has cat");
return true;
}
}

Inject Serilog's ILogger interface in ASP .NET Core Web API Controller

All the examples I can find about using Serilog in an ASP .NET Core Web Application use Microsoft's ILogger<T> interface instead of using Serilog's ILogger interface.
How do I make it so that Serilog's ILogger can be injected via constructor, instead?
using Serilog;
public class HomeController : Controller
{
ILogger logger;
public HomeController(ILogger logger)
{
this.logger = logger;
}
public IActionResult Index()
{
this.logger.Information("Index was called");
return View();
}
}
If you prefer ILogger instead of ILogger<HomeController>, you could try to register ILogger.
Here are two options to use Serialog.Information.
Use Log.Logger
Log.Logger.Information("Information Log from Log.Logger");
Register ILogger
//Startup.cs
services.AddSingleton(Log.Logger);
//Use
public class HomeController : Controller
{
private readonly ILogger _logger;
public HomeController(ILogger logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.Information("Inform ILog from ILogger");
return View();
}
}
You can install Serilog as the logger under the Microsoft logging framework by including the Serilog.Extensions.Logging package and including the following in your app startup:-
public void ConfigureServices(IServiceCollection services)
{
services.AddLogging(x =>
{
x.ClearProviders();
x.AddSerilog(dispose: true);
});
...
Or, as an alternative to injecting, if you just want a reference to the Serilog logger, Serilog.Log has a static method Log to create a logger...
...
using Serilog;
...
namespace Test.Controllers
{
public class TestController : Controller
{
private readonly static ILogger log = Log.ForContext(typeof(TestController));
public TestController()
{
log.Debug("Test");
}

Dependency inject a class that has a dependency injection form DbContext

How can I inject this:
private readonly CarModelsController _carModelsController;
public AdminController(CarModelsController carModelsController)
{
_carModelsController = carModelsController;
}
When the CarModelsController looks like this:
[ApiController]
public class CarModelsController : ControllerBase
{
private readonly ApplicationDbContext _context;
public CarModelsController(ApplicationDbContext context)
{
_context = context;
}
I need to have the DbContext when I inject it? Should it be done in another way? What's the correct way to go here? I've never learned this.
I would advise you review the choice of injecting controllers into each other.
Create a service abstraction and class that holds the Db related actions
public interface IDataService {
//...expose desired members
}
public class DataService: IDataService {
private readonly ApplicationDbContext context;
public DataService(ApplicationDbContext context) {
this.context = context;
}
//...other members implemented
}
and inject that into your controllers.
public class AdminController: ControllerBase {
private readonly IDataService service;
public AdminController(IDataService service) {
this.service = service
}
//...
}
[ApiController]
public class CarModelsController : ControllerBase
private readonly IDataService service;
public CarModelsController(IDataService service) {
this.service = service
}
//...
}
All that is left is to register all dependencies with the DI container at startup in the composition root.
Assuming default .Net Core DI
services.AddDbContext<ApplicationDbContext>(...);
services.AddScoped<IDataService, DataService>();
Reference Dependency injection in ASP.NET Core
You nedd to inject your dependencies into the startup class ConfigureServices method.
public void ConfigureServices (IServiceCollection services) {
services.AddScoped<DbContext, Your_Project_DbContext> ();
services.AddScoped<Your_Interface, Your_Concrete_Class> ();
}

DI ILogger with Serilog on Webapi 2 running Asp.Net Core 2

I am trying to integrate Serilog to my WebApi 2 with Asp.Net Core 2 (With MSSQLServer integration).
I have added the nuget packages and then added the following to my
public async void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
var log = new LoggerConfiguration()
.WriteTo.MSSqlServer(DbGlobals.DevDatabase, "Logs")
.CreateLogger();
loggerFactory.AddSerilog(log);
The in my Program.cs I have the default;
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.Build();
From reading the MSDN docs .CreateDefaultBuilder(args) should include logging?
However, when I then DI the ILogger to my controller;
[Route("api/[controller]")]
public class TraderController : Controller
{
private TraderService _service;
private readonly ILogger _logger;
public TraderController(Func<IBemfeitoDataContext> context, ILogger logger)
{
_service = new TraderService(context, logger);
_logger = logger;
}
I am getting the following error;
InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'WebApi.Controllers.TraderContactController'.
Do I need to physically setup a singleton for ILogger in the Startup.cs. Can anyone tell me what I am missing here? As I assumed because logging is build into the Core pipeline this would be something it knew how to resolve?
You need to refactor the controller to expect the generic logger ILogger<T>, which is derived from ILogger
[Route("api/[controller]")]
public class TraderController : Controller {
private TraderService _service;
private readonly ILogger _logger;
public TraderController(
Func<IBemfeitoDataContext> context,
ILogger<TraderController> logger //<-- note the change here
) {
_service = new TraderService(context, logger);
_logger = logger;
}
}
ILogger<> is mapped to Logger<> when .AddLogging() is called within CreateDefaultBuilder. ILogger is not registered directly with the service collection.
With that done, the current design choice of coupling the controller to implementation concerns (i.e TraderService) was a cause for some concern.
assuming based on how the current code is being used
public class TraderService : ITraderService {
private readonly ILogger logger;
public TraderService(Func<IBemfeitoDataContext> context, ILogger logger) {
this.logger = logger;
//...
}
//...code removed for brevity
}
the service should also be fixed to depend on ILogger<T>
public class TraderService : ITraderService {
private readonly ILogger logger;
public TraderService(Func<IBemfeitoDataContext> context, ILogger<TraderService> logger) {
this.logger = logger;
//...
}
//...code removed for brevity
}
and the controller should be refactored to depend on the service abstraction and not the implementation.
[Route("api/[controller]")]
public class TraderController : Controller {
private readonly ITraderService service;
private readonly ILogger logger;
public TraderController(ITraderService service, ILogger<TraderController> logger) {
this.service = service;
this.logger = logger;
}
//...
}
All classes involved will get their dependencies explicitly injected when resolved.
This answer assumes that ITraderService and TraderService are registered with the DI container.
Both ILoggerFactory and generic ILogger<T> are injected. That means you could have your controller like this:
[Route("api/[controller]")]
public class TraderController : Controller {
private readonly ITraderService service;
private readonly ILogger logger;
public TraderController(ITraderService service, ILoggerFactory loggerFactory)
{
this.service = service;
this.logger = loggerFactory.CreateLogger<TraderController>();
}
//...
}

Categories

Resources