9
votes

My first little venture into the .Net Core libraries using the new ConfigurationBuilder, and Options pattern.

Lot's of good examples here: https://docs.asp.net/en/latest/fundamentals/configuration.html and a good copy of the example here

Item 1. it says this can be used with non MVC applications, but no examples on how to use it without MVC - particularly if you are using a custom, strongly-typed class. I would like to see an example of showing the setup of DependencyInjection, Configuration, and Logging using a Console application.

Item 2. it says you can write back, but no examples or documentation as to how to persist any changes back to the file store. I would like to see an example of how persist changes back into the configuration using a strongly typed class. In both Json or XML?

Item 3. all examples require a hand bombed initial file - would like to see an example where the initial json/xml file is created from a strongly-typed class (comes in handy when there are many parameters for the application).

If I can spend enough time on this (rather than re-post an example already in the documentation) I'll do it! If you know of a post/documentation that will help me, I would appreciate it.

1
You say you have question, but I don't see any question, only complaining about missing examples. If you're asking for those examples, then that's not what SO is for.svick
I can' find any examples or documentation what I'm looking for, I'm hoping that another developer can point me in the right direction, or point me to some documentation.codeputer
Microsoft welcomes the community to write up such topics on its documentation sites as well as Stack Overflow Documentation. You might keep an eye on them or raise a request there. A fast moving platform like this makes it boring to document, so I am not surprised that many things are missing.Lex Li

1 Answers

20
votes

How do I configure a .NET Core 1.0.0 Console Application for Dependency Injection, Logging and Configuration?

A lot of what was written is deprecated after RC2. (see issue). Fortunatelly there are some updated posts with excelent info:

Essential .NET - Dependency Injection with .NET Core

Essential .NET - Logging with .NET Core

I came up with the following solution. I bet there are things that can be improved, please leave comments so I can improve this answer.

In my static void Main, I

  • Setup Dependency injection
  • Invoke ConfigureServices
  • Instantiate my Application class using DI
  • Switch from 'sync Main' to 'async Application.Run()' (It makes sense to me to switch to async as soon as possible and only once.)

On my Application Class:

  • I inject as much as possible on the class constructor.
  • Catch any exception on the Run() method.

Here is the code.

using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Configuration;
using System.IO;

public class Program
{
    static void Main(string[] args)
    {
        IServiceCollection serviceCollection = new ServiceCollection();

        ConfigureServices(serviceCollection);

        // Application application = new Application(serviceCollection);
        IServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();

        var app = serviceProvider.GetService<Application>();

        // For async
        Task.Run(() => app.Run()).Wait(); // Exceptions thrown here will be lost! Catch them all at Run()
        // Otherwise use sync as in: app.Run();            
    }

    private static void ConfigureServices(IServiceCollection services)
    {
        ILoggerFactory loggerFactory = new LoggerFactory()
            .AddConsole()
            .AddDebug();

        services.AddSingleton(loggerFactory); // Add first my already configured instance
        services.AddLogging(); // Allow ILogger<T>

        IConfigurationRoot configuration = GetConfiguration();
        services.AddSingleton<IConfigurationRoot>(configuration);

        // Support typed Options
        services.AddOptions();
        services.Configure<MyOptions>(configuration.GetSection("MyOptions"));  

        services.AddTransient<Application>();
    }

    private static IConfigurationRoot GetConfiguration()
    {
        return new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile($"appsettings.json", optional: true)
            .Build();
    }
}

public class MyOptions
{
    public string Name { get; set; }
}

public class Application
{
    ILogger _logger;
    MyOptions _settings;

    public Application(ILogger<Application> logger, IOptions<MyOptions> settings)
    {
        _logger = logger;
        _settings = settings.Value;
    }

    public async Task Run()
    {
        try
        {
            _logger.LogInformation($"This is a console application for {_settings.Name}");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex.ToString());
        }
    }
}
}

The AppSettings.json file:

{
  "MyOptions": {
    "Name" : "John"
  }
}

And the project.json file:

 "dependencies": {
    "Microsoft.Extensions.Configuration": "1.0.0",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
    "Microsoft.Extensions.Configuration.Json": "1.0.0",
    "Microsoft.Extensions.DependencyInjection": "1.0.0",
    "Microsoft.Extensions.Logging": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Extensions.Logging.Debug": "1.0.0",
    "Microsoft.Extensions.Options": "1.0.0",
    "Microsoft.Extensions.PlatformAbstractions": "1.0.0",
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0",

On your question #2: I've read the document and unless I am missing something, it does not says you can write configuration. I'm not sure you can do that, unless you edit the JSON files manually using Newtonsoft.JSON.

If a name/value pair is written to Configuration, it is not persisted. This means that the written value will be lost when the sources are read again.

For your question #3 I've included a default AppSettings.json file. Your config should have a Section where its settings match by name to the public properties of your settings class.