System.Configuration.ConfigurationManager in Core

on Monday, August 13, 2018

The .NET Core (corefx) issue, System.Configuration Namespace in .Net Core, ends with the question:

@weshaggard Can you clarify the expectations here for System.Configuration usage?

I was recently converting a .NET Full Framework library over to a .NET Standard library and ran into the exact problem in that issue, and I also got stuck trying to figure out “When and How are you supposed to use System.Configuration.ConfigurationManager?”

I ended up with the answer:

If at all possible, you shouldn’t use it. It’s a facade/shim that only works with the .NET Full Framework. It’s exact purpose is to allow .NET Standard libraries to compile; but it doesn’t work unless the runtime is .NET Full Framework. In order to properly write code using it in a .NET Standard library you will have to use compiler directives to ensure that it doesn’t get executed in a .NET Core runtime. It’s scope, purpose and usage is very limited.

In a .NET Standard library if you want to use configuration information you need to plan for two different configuration systems.

  • .NET Full Framework Configuration

    Uses ConfigurationManager from the System.Configuration dll installed with the framework. This uses the familiar Configuration.AppSettings[string] and Configuration.ConnectionStrings[string]. This is a unified model in .NET Full Framework and works across all application types: Web, Console, WPF, etc.

  • .NET Core Configuration

    Uses ConfigurationBuilder from Microsoft.Extensions.Configuration. And, really, it expects ConfigurationBuilder to be used in an ASP.NET Core website. And this is the real big issue. The .NET Core team focused almost solely on ASP.NET Core and other target platforms really got pushed to the side. Because of this, it’s expecting configuration to be done through the ASP.NET Configuration system at Startup.

And, for now, I can only see two reasonable ways to implement this:

  • A single .NET Standard Library that uses compiler directives to determine when to use ConfigurationManager vs a ConfigurationBuilder tie-in.

    This would use the System.Configuration.ConfigurationManager nuget package.

    Pros:
    - Single library with a single nuget package
    - Single namespace

    Cons:
    - You would need a single “Unified Configuration Manager” class which would have #ifdef statements throughout it to determine which configuration system to use.
    - If you did need to reference either the .NET Full Framework or .NET Core Framework the code base would become much more complicated.
    - Unit tests would also need compiler directives to handle differences of running under different Frameworks.
  • A common shared project used in two libraries each targeting the different frameworks.

    This would not use the System.Configuration.ConfigurationManager nuget package.

    This is how the AspNet API Versioning project has handled the situation.

    Pros:
    - The two top-level libraries can target the exact framework they are intended to be used with. They would have access to the full API set of each framework and would not need to use any shims/facades.
    - The usage of #ifdef statements would be uniform across the files as it would only need to be used to select the correct namespace and using statements.
    - The code would read better as all framework specific would be abstracted out of the shared code using extension methods.

    Cons:
    - You would create multiple libraries and multiple nuget packages. This can create headaches and confusion for downstream developers.
    - Unit tests would (most likely) also use multiple libraries, each targeting the correct framework.
    - Requires slightly more overhead to ensure libraries are versioned together and assembly directives are setup in a shared way.
    - The build system would need to handle creating multiple nuget packages.

0 comments:

Post a Comment


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.