DEV Community

Masui Masanori
Masui Masanori

Posted on

3

【.NET Core】Play with Console App

Intro

I have developed ASP.NET Core applications for several years.
But I have little experience developing Console applications of .Net Core.

So in this time, I try Console application.

Can I develop like ASP.NET Core(ex. using DI, outputting logs, etc)?

Environments

  • .NET Core ver.5.0.100-preview.7.20366.6

Base project

I create a Console application.

Program.cs

using System;

namespace ConsoleSample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Loading Config files

I want to use config values like connection strings for connecting Database.

Of course I can load JSON files with StreamReader, etc. But is there any simple way like ASP.NET Core?

Startup.cs

...
    private readonly IConfiguration configuration;
    public Startup(IHostEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", false, true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", false, true)
            .AddEnvironmentVariables();
        configuration = builder.Build();
    }
...
Enter fullscreen mode Exit fullscreen mode

Install

To use ConfigurationBuilder, I installed some packages.

  • Microsoft.Extensions.Configuration ver.5.0.0-preview.7.20364.11
  • Microsoft.Extensions.Configuration.FileExtensions ver.5.0.0-preview.7.20364.11
  • Microsoft.Extensions.Hosting ver.5.0.0-preview.7.20364.11
  • Microsoft.Extensions.Configuration.Json ver.5.0.0-preview.7.20364.11

Samples

I add JSON files, and loading functions into Program.cs.

appsettings.json

{
    "ConnectionStrings": "Host=localhost;Port=5432;Database=Example;Username=postgres;Password=example"
}
Enter fullscreen mode Exit fullscreen mode

appsettings.Development.json

{
    "Message": "Hello Development"
}
Enter fullscreen mode Exit fullscreen mode

appsettings.Production.json

{
    "Message": "Hello Production"
}
Enter fullscreen mode Exit fullscreen mode

Program.cs

using System;
using Microsoft.Extensions.Configuration;

namespace ConsoleSample
{
    class Program
    {
        static void Main(string[] args)
        {
            var config = GetConfiguration();
            Console.WriteLine(config["ConnectionStrings"]);
            Console.WriteLine("Hello World!");
        }
        private static IConfiguration GetConfiguration()
        {
            var builder = new ConfigurationBuilder()
            .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
            .AddJsonFile("appsettings.json", false, true)
            .AddEnvironmentVariables();
            return builder.Build();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

I also can use "System.IO.Directory.GetCurrentDirectory()" to set Base Path.

Get EnvironmentName

I want to load "appsettings.Development.json" for Debug mode.
And When I execute with Release mode, I want to load "appsettings.Production.json".

For ASP.NET Core projects, it may be set EnvironmentName automatically.

So if I set EnvironmentName, I can get EnvironmentName like this.

var environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
Enter fullscreen mode Exit fullscreen mode

Is there more simple way?
So I choose using #if preprocessor directive.

        private static IConfiguration GetConfiguration()
        {
            var builder = new ConfigurationBuilder()
                .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                .AddJsonFile("appsettings.json", false, true)
#if DEBUG
                .AddJsonFile($"appsettings.Development.json", false, true)
#else
                .AddJsonFile($"appsettings.Production.json", false, true)
#endif
                .AddEnvironmentVariables();
            return builder.Build();
        }
Enter fullscreen mode Exit fullscreen mode

DI(Dependency Injection)

I also can use DI in Console applications.

Install

  • Microsoft.Extensions.DependencyInjection ver.5.0.0-preview.7.20364.11

Samples

IProductService.cs

namespace Products
{
    public interface IProductService
    {       
    }
}
Enter fullscreen mode Exit fullscreen mode

ProductService.cs

namespace Products
{
    public class ProductService: IProductService
    {       
    }
}
Enter fullscreen mode Exit fullscreen mode

MainController.cs

using System;
using System.Threading.Tasks;
using Products;

namespace Controllers
{
    public class MainController
    {
        private readonly IProductService _product;
        public MainController(IProductService product)
        {
            _product = product;
        }
        public async Task StartAsync()
        {
            await Task.Run(() => Console.WriteLine(_product == null));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Program.cs

using System;
using System.Threading.Tasks;
using Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Products;

namespace ConsoleSample
{
    class Program
    {
        static async Task Main(string[] args)
        {
...
            var servicesProvider = BuildDi();
            using (servicesProvider as IDisposable)
            {
                var mainController = servicesProvider.GetRequiredService<MainController>();
                await mainController.StartAsync();
            }
        }
...
        private static IServiceProvider BuildDi()
        {
            var services = new ServiceCollection();
            services.AddTransient<MainController>();
            services.AddScoped<IProductService, ProductService>();
            return services.BuildServiceProvider();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Inject IConfiguration

In ASP.NET Core applications, I can use IConfiguration in Controller classes without constructor injection.
But in Console applications, I must add it into IServiceProvider.

Program.cs

...
        private static IServiceProvider BuildDi()
        {
            var services = new ServiceCollection();

            services.AddSingleton<IConfiguration>(GetConfiguration());

            services.AddTransient<MainController>();
            services.AddScoped<IProductService, ProductService>();
            return services.BuildServiceProvider();
        }
...
Enter fullscreen mode Exit fullscreen mode

Now I can get IConfiguration by constructor injection.

MainController.cs

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Products;

namespace Controllers
{
    public class MainController
    {
        private readonly IProductService _product;
        public MainController(IConfiguration config,
            IProductService product)
        {

            Console.WriteLine(config["Message"]); // <- print "Hello Development"
            _product = product;
        }
Enter fullscreen mode Exit fullscreen mode

using Entity Framework Core

As same as ASP.NET Core, I can use Entity Framework Core to access Database.

Install

  • Microsoft.EntityFrameworkCore ver.5.0.0-preview.7.20365.15
  • Microsoft.EntityFrameworkCore.Relational ver.5.0.0-preview.7.20365.15
  • Microsoft.EntityFrameworkCore.Abstractions ver.5.0.0-preview.7.20365.15
  • Npgsql.EntityFrameworkCore.PostgreSQL ver.5.0.0-preview7-ci.20200722t163648

ConsoleSampleContext.cs

using Microsoft.EntityFrameworkCore;

namespace Models
{
    public class ConsoleSampleContext: DbContext
    {
        public ConsoleSampleContext(DbContextOptions<ConsoleSampleContext> options)
            :base(options)
        {
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Program.cs

...
        private static IServiceProvider BuildDi()
        {
            var config = GetConfiguration();
            var services = new ServiceCollection();
            services.AddSingleton<IConfiguration>(config);

            services.AddDbContext<ConsoleSampleContext>(options =>
                options.UseNpgsql(config["ConnectionStrings"]));

            services.AddTransient<MainController>();
            services.AddScoped<IProductService, ProductService>();
            return services.BuildServiceProvider();
        }
...
Enter fullscreen mode Exit fullscreen mode

Output logs

I use NLog to output logs.

Install

  • NLog ver.4.7.3
  • NLog.Extensions.Logging ver.1.6.4

Samples

nlog.config

<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">

    <targets>
        <target xsi:type="Console" name="outputconsole"
            layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" />

        <target xsi:type="File" name="outputfile" fileName="C:\tmp\logs\ConsoleSample\${date:format=yyyy}\${date:format=MM}\${shortdate}.log"
            layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
    </targets>

    <rules>
        <logger name="*" minlevel="Debug" writeTo="outputconsole" />
        <!--Microsoft.* のクラスの Info レベル以下のログはスキップ-->
        <logger name="Microsoft.*" maxLevel="Info" final="true" />
        <logger name="*" minlevel="Debug" writeTo="outputfile" />
    </rules>
</nlog>
Enter fullscreen mode Exit fullscreen mode

ConsoleSample.csproj

...
  <ItemGroup>
    <Content Include="nlog.config">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="appsettings.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="appsettings.Development.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
    <Content Include="appsettings.Production.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
</Project>
Enter fullscreen mode Exit fullscreen mode

NLog ver.5.0.0-beta11

I got error with NLog ver.5.0.0-beta11.

Attempt by method 'NLog.Extensions.Logging.ConfigureExtensions.CreateNLogLoggerProvider(System.IServiceProvider, Microsoft.Extensions.Configuration.IConfiguration, NLog.Extensions.Logging.NLogProviderOptions, NLog.LogFactory)' to access method 'NLog.LogManager.get_LogFactory()' failed.
Enter fullscreen mode Exit fullscreen mode

Maybe because some changes of ver.5.0.0.

At least now(2020-08-09), if you want to use these samples. you should use ver.4.7.3.

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay