9

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.

Cœur
  • 37,241
  • 25
  • 195
  • 267
codeputer
  • 1,987
  • 3
  • 19
  • 45
  • 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 Aug 01 '16 at 20:45
  • 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 Aug 02 '16 at 01:37
  • 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 Aug 02 '16 at 02:04

1 Answers1

20

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.

Gerardo Grignoli
  • 14,058
  • 7
  • 57
  • 68
  • What is really missing from the Article link, is the Using statements (and related NuGet packages needed) to gain access to the extension methods. Lesson learned - be wary of extension methods in .Net core! – codeputer Aug 03 '16 at 16:30
  • Still fighting with reading from an XML file, as opposed to JSON. Ryan Crawford tweeted me to include .Extention.Configuration.XML, but I'm getting a UTF-16 exception (unable to convert?). – codeputer Aug 03 '16 at 16:31
  • wow I havent seen UTF-16 for a while... Things to check is your text file encoding (on notepad: save as -> Encoding) and your `` tag. I suggest to start with a plain simple XML file created with notepad or vi first. (do not copy paste, just type). Once that is working, try to increase the xml. – Gerardo Grignoli Aug 03 '16 at 17:39
  • Is the XML configuration? or is it just data? you can read it with `System.Xml.Linq.XDocument` also. – Gerardo Grignoli Aug 03 '16 at 17:42
  • Check out sample XML configuration usage sample here: http://whereslou.com/2014/05/23/asp-net-vnext-moving-parts-iconfiguration/ – Gerardo Grignoli Aug 03 '16 at 18:45
  • Gerardo - based on your blog, I got rid of the error by simply removing the from the top of the XML. I created this XML by serializing a class through XmlSerializXML. This class is going to be representative of a large configuration file - one class, with a number of properties - and I would like to rehydrate the class on startup. My theory is that if the file is not there it can be created by serializing out a class with default values. – codeputer Aug 04 '16 at 00:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/120060/discussion-between-gerardo-grignoli-and-codputer). – Gerardo Grignoli Aug 04 '16 at 00:54
  • 1
    Would be nice to have an update of that for .net core 2.0 – zaitsman Aug 24 '17 at 01:40
  • I got null value at `var app = serviceProvider.GetService()`. https://stackoverflow.com/questions/45928025/net-core-2-0-console-program-got-null-value-when-running-serviceprovider-getse – ca9163d9 Aug 28 '17 at 22:32