Emanuele Lacopo
Emanuele Lacopo

Reputation: 51

How to use logging to NET core Console Application that uses Dependency Injection

I have a project .Net Core in React and, to save time, I would like to test a method to export files by a Console Application. But I can't to implement the DI in my console, here's the error:

Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger`1[MyPrj.Managers.Managers.Implementations.MyLogManager]' while attempting to activate 'MyPrj.Managers.Managers.Implementations.MyLogManager'.

This is a simplified version of my Program.cs:

class Program
{
    public static IConfigurationRoot Configuration;
    public static ServiceProvider serviceProvider;

    public static void Main(string[] args)
    {
        var services = new ServiceCollection();
        var builder = new ConfigurationBuilder()
            .SetBasePath(Path.Combine(AppContext.BaseDirectory))
            .AddJsonFile("appsettings.json", optional: true);

        Configuration = builder.Build();

        services.AddDbContext<MyDBContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        services.Configure<MailOptions>(Configuration.GetSection("EmailSettings"));
        [... other options...]

        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<ILogManager, MyLogManager>();

        services.AddScoped<IMailManager, MailManager>();
        [... other services ...]
        services.AddScoped<IDocumentationManager, DocumentationManager>();

        serviceProvider = services.BuildServiceProvider();

        MainAsync().GetAwaiter().GetResult();

        Console.WriteLine("END");
        Console.ReadKey();
    }

    private static async Task MainAsync()
    {
        await ExportAsync();
    }

    public static async Task ExportAsync()
    {
        using (MyDBContext dbContext = serviceProvider.GetService<MyDBContext>())
        {
            List<User> user = dbContext.Users.ToList();
            
            var logger = serviceProvider.GetService<ILogManager>();
            var docManager = serviceProvider.GetService<IDocumentationManager>();
            
            string userAnswer = Console.ReadLine();

            var file = await docManager.GetUser(userAnswer);

            File.WriteAllBytes("C:\tmp\user.txt", file.File);
        }
    }
}

Upvotes: 0

Views: 2851

Answers (3)

Emanuele Lacopo
Emanuele Lacopo

Reputation: 51

Thanks to all, it has been enough adding services.AddLogging(), following @Steven 's advice, to solve my problem.

Upvotes: 1

You can use a HostedService for encapsulating the StartAsync and StopAsync, making the code more elegancy.

public class HostedService : IHostedService
{
    private readonly ISolrSeeder _seeder;

    public HostedService(ISolrSeeder seeder)
    {
        _seeder = seeder;
    }

    public async Task StartAsync(CancellationToken cancellationToken)
        => await _seeder.SeedAsync(cancellationToken);

    public async Task StopAsync(CancellationToken cancellationToken) => 
        await Task.Run(() => Environment.Exit(Environment.ExitCode), cancellationToken);
}

And then, you can make your program.cs represents the startup from a console application, considering many environments.

internal class Program
{
    private const string SettingsName = "appsettings";
    private const string SettingsExtention = ".json";
    private const string AppSettings = SettingsName + SettingsExtention;

    public static async Task Main(string[] args)
        => await new HostBuilder()
            .ConfigureHostConfiguration(configHost =>
            {
                configHost
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile(AppSettings, true, true)
                    .AddEnvironmentVariables()
                    .AddCommandLine(args);
            })
            .ConfigureAppConfiguration((hostContext, configApp) =>
            {
                configApp
                    .SetBasePath(Directory.GetCurrentDirectory())
                    .AddJsonFile(AppSettings, true, true)
                    .AddJsonFile(SettingsName + "." + hostContext.HostingEnvironment.EnvironmentName + SettingsExtention, true, true)
                    .AddEnvironmentVariables()
                    .AddCommandLine(args);
            })
            .ConfigureServices((hostContext, services) =>
            {
                services
                    .AddLogging()
                    .AddRepositories()
                    .AddDbContext(options => options.ConnectionString = hostContext.Configuration.GetConnectionString("DefaultConnection"))
                    .AddSolr(options =>
                    {
                        options.BaseAddress = hostContext.Configuration["Solr:BaseAddress"];
                        options.Core = hostContext.Configuration["Solr:Core"];
                    })
                    .AddScoped<ISolrSeeder, SolrSeeder>()
                    .AddHostedService<HostedService>();
            })
            .ConfigureLogging((hostContext, configLogging) =>
            {
                configLogging.AddConsole();
            })
            .UseConsoleLifetime()
            .Build()
            .RunAsync();
}

The rest of the code is available on this repository.

Upvotes: 1

ddfra
ddfra

Reputation: 2565

Since you are creating your console app from scratch you have to manually configure the logger, otherwise it would not be injected.

var loggerFactory = LoggerFactory.Create(builder =>
        {
            builder
                .AddFilter("Microsoft", LogLevel.Warning)
                .AddFilter("System", LogLevel.Warning)
                .AddFilter("LoggingConsoleApp.Program", LogLevel.Debug)
                .AddConsole()
                .AddEventLog();
        });
        ILogger logger = loggerFactory.CreateLogger<Program>();
        logger.LogInformation("Example log message");
        services.AddSingleton<ILoggerFactory>(loggerFactory);

public class MyLogManager : ILogManager {
    private readonly ILogger<MyLogManager> logger;

    public MyLogManager(ILoggerFactory factory) {
        logger = factory.CreateLogger<MyLogManager>();
    }
}

you can find more here https://learn.microsoft.com/aspnet/core/fundamentals/logging/?view=aspnetcore-3.1

Upvotes: 4

Related Questions