DEV Community

Ballcapz
Ballcapz

Posted on • Edited on

Adding Dependency Injection to .NET Core Console Applications on Windows

App.cs

  1. Add App.cs file to the project
  2. Add a Run method to the App.cs file, as shown below
// This is now equivalent to Main in Program.cs
public void Run()
{
    Console.WriteLine("Hello from App.cs");
}
Enter fullscreen mode Exit fullscreen mode

The App.cs class that will be used to run the application.
Program.cs will be used to do the setup and register the IOC container, and the App.cs will contain all of the running console application code.

appsettings.json

Add a json configuration file to the project and name it appsettings.json

alt text

  1. Install Nuget Package Microsoft.Extensions.DependencyInjection
  2. Install Nuget Package Microsoft.Extensions.Configuration
  3. Install Nuget Package Microsoft.Extensions.Configuration.Binder
  4. Install Nuget Package Microsoft.Extensions.Configuration.Json
  5. IMPORTANT: Open appsettings.json properties, and change Copy To Output Directory, to Copy if newer or Copy always

alt text

  • Add the following to Program.cs
static void Main(string[] args)
{
    var services = ConfigureServices();

    var serviceProvider = services.BuildServiceProvider();

    // calls the Run method in App, which is replacing Main
    serviceProvider.GetService<App>().Run();
}

private static IServiceCollection ConfigureServices()
{
    IServiceCollection services = new ServiceCollection();

    var config = LoadConfiguration();
    services.AddSingleton(config);

    // required to run the application
    services.AddTransient<App>();

    return services;
}

public static IConfiguration LoadConfiguration()
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);

    return builder.Build();
}
Enter fullscreen mode Exit fullscreen mode

This registers the appsettings.json with the .net core Dependency Injection container, and allows us to use the configuration file for things like connection strings and logging directories.

Using Configuration In The App

  • Dependency Inject the registered configuration
// in App.cs
private readonly IConfiguration _config;

public App(IConfiguration config)
{
    _config = config;
}
Enter fullscreen mode Exit fullscreen mode
  • Add a configuration section and value to appsettings.json:
{
    "Runtime": {
    "LogOutputDirectory": "C:\\temp\\programLog.txt"
   }
}
Enter fullscreen mode Exit fullscreen mode
  • Use this configuration in App.cs
public void Run()
{
    var logDirectory = _config.GetValue<string>("Runtime:LogOutputDirectory");
    // Using serilog here, can be anything
    var log = new LoggerConfiguration()
        .WriteTo.Console()
        .WriteTo.File(logDirectory)
        .CreateLogger();

    log.Information("Serilog logger information");
    Console.WriteLine("Hello from App.cs");
}
Enter fullscreen mode Exit fullscreen mode

Register Interfaces with Concrete Objects

  1. Add the files IUser.cs and User.cs to the project
  2. In the Program.cs method ConfigureServices() add:
services.AddTransient<IUser, User>();
Enter fullscreen mode Exit fullscreen mode

Which makes the ConfigureServices() look like:

private static IServiceCollection ConfigureServices()
{
    IServiceCollection services = new ServiceCollection();

    var config = LoadConfiguration();
    services.AddSingleton(config);

    services.AddTransient<IUser, User>();

    services.AddTransient<App>();

    return services;
}
Enter fullscreen mode Exit fullscreen mode

This allows us to write our code against our interface. In order to do so, we need to "inject" the interface into our App.cs

private readonly IConfiguration _config;
private readonly IUser _user;

public App(IConfiguration config, IUser user)
{
    _config = config;
    _user = user;
}

...
// using the IUser
_user.TruncateName("Jerry     ");
...
Enter fullscreen mode Exit fullscreen mode

Conclusion

Setting up dependency injection and configuration in this manner allows us to use configuration easily throughout our Console applicaiton, as well as giving us the ability to program against interface. This helps keep our code losely coupled and testable, along with giving us the ability to extend our application easily beyond the scope of a Console application.

Code Example On Github:
https://github.com/Ballcapz/Console-Application-Dependency-Injection

Link To Original Post:
https://www.ballcapz.dev/blog/dotnet-core-dependency-injection/

Top comments (5)

Collapse
 
firewater profile image
firewater

Thanks! How would I use Serilog from the User class, for example?

Collapse
 
hk77921 profile image
hk77921

Very Nicely crafted article.

Collapse
 
mincasoft profile image
mincasoft

Nice article

Collapse
 
ralpharama profile image
Ralph Capper

Thanks! Great guide.

Collapse
 
longkhoa profile image
LongKhoa

Thank for helper, It's very useful