.NET と.NET Coreで定義ファイルを読む

.NETのアプリケーションにはアプリケーション設定ファイルから定義を読み取る機能が付いています。自作の定義フォーマットを作成せずとも定義が読み込めたりします。

そこで、.NET Framework と.NET Coreの両方から読み取ってみようと思います。

.NET Frameworkで定義ファイルを読む

.NET Frameworkの既定の定義ファイルはApp.configという固定名のXMLファイルになります。読み込むための専用クラスがライブラリに最初から用意されているのでそれを利用する形になります。

まず、プロジェクト参照に以下アセンブリを追加してください。

System.Configuration

次にプロジェクト直下にある"App.Config"(無ければ追加します)へ以下のように読みたい定義を追記します。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
    </startup>
    <!-- ↓↓↓ここを追加↓↓↓ -->
    <appSettings>
        <add key="setting_string" value="abcdefg"/>
        <add key="setting_bool" value="true"/>
        <add key="setting_int" value="10"/>
        <add key="setting_double_1" value="3.1415926535"/>
        <add key="setting_double_2" value="2.43E-2"/>
    </appSettings>
    <!-- ↑↑↑ここを追加↑↑↑ -->
</configuration>

次に、コードを以下のように記述します。

using System;
using System.Configuration;

internal class AppMain
{
    public static void Main(string[] args)
    {
        Console.WriteLine("setting_string = " + ConfigUtil.GetValue("setting_string"));
        Console.WriteLine("setting_bool = " + ConfigUtil.GetValue<bool>("setting_bool"));
        Console.WriteLine("setting_int = " + ConfigUtil.GetValue<int>("setting_int"));
        Console.WriteLine("setting_double_1 = " + ConfigUtil.GetValue<double>("setting_double_1"));
        Console.WriteLine("setting_double_2 = " + ConfigUtil.GetValue<double>("setting_double_2"));
    }
}

上記コードを実行すると以下の出力になります。

setting_string = abcdefg
setting_bool = True
setting_int = 10
setting_double_1 = 3.1415926535
setting_double_2 = 0.0243

前述のコード内で使用しているConfigUtilは以下の通りです。GetValueで全て定義を取れるようにしています。

public static class ConfigUtil
{
    public static string GetValue(string key)
    {
        return ConfigurationManager.AppSettings[key];
    }

    public static T GetValue<T>(string key)
    {
        if (typeof(T) == typeof(bool))
        {
            return (T)(object)bool.Parse(GetValue(key));
        }

        if (typeof(T) == typeof(int))
        {
            return (T)(object)int.Parse(GetValue(key));
        }

        if(typeof(T) == typeof(double))
        {
            return (T)(object)double.Parse(GetValue(key));
        }

        throw new NotSupportedException(typeof(T).Name + " is notsuprted.");
    }
}

.NET Coreで定義ファイルを読む

.NET Coreで定義ファイルはJson形式です。F/Wと違い、特に決まった名前のファイルはありません。従ってなので自分で好きなファイルを作成し定義ファイルにします。ここでは .NET F/Mにあやかって "App.Config.json" という名前で作成します。

読み書きするパッケージがデフォルトでは存在しないため、プロジェクトへ以下のパッケージをNuGetより追加します。

ついでに.NET FrameworkのXMLも読もうと思うので3つめにXML用のパッケージも追加します。

Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Json

ちなみに、Microsoft.AspNetCoreがNuGetで入っている前提で書いています。動かない場合、以下依存関係が成立してるかご確認ください。

// Microsoft.AspNetCoreの依存関係
Microsoft.Extensions.Configuration.Json
Microsoft.Extensions.Configuration.EnvironmentVariables
Microsoft.Extensions.Configuration.CommandLine
Microsoft.AspNetCore.Server.IISIntegration
Microsoft.Extensions.Configuration.UserSecrets
Microsoft.AspNetCore.Routing
Microsoft.AspNetCore.Server.Kestrel.Https
Microsoft.AspNetCore.HostFiltering
Microsoft.AspNetCore.Server.Kestrel
Microsoft.Extensions.Logging
Microsoft.AspNetCore.Diagnostics
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.AspNetCore.Hosting
Microsoft.Extensions.Logging.Debug
Microsoft.Extensions.Logging.Console
Microsoft.Extensions.Logging.Configuration

次に、定義ファイルを以下の通り記述します。追加後、ファイルの属性を出力フォルダへ新しければコピーに設定します。

{
    "appSettings_2": {
        "setting_string_2": "abcdefg2",
        "setting_bool_2": "false",
        "setting_int_2": "20",
        "setting_double_1_2": "1.23456",
        "setting_double_2_2": "5.22E-6"
    }
}

次に、コードを以下のように記述します。

using Microsoft.Extensions.Configuration;
using System;

internal class AppMain
{
    internal static void Main(string[] args)
    {
        // exeと同じフォルダにある定義ファイルを指すための指定
        string basePath = Directory.GetCurrentDirectory();
        // (万が一自前で)Windowsサービス化している場合こっちを使う
        // string basePath = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);

        IConfigurationRoot configuration = new ConfigurationBuilder()
            .SetBasePath(basePath)
            .AddJsonFile("App.config.json", optional: true)
            //.AddXmlFile("App.config") import Microsoft.Extensions.Configuration.XML
            .AddEnvironmentVariables() // 必要であれば追加
            .Build();

        Console.WriteLine("setting_string_2 = " + configuration["appSettings_2:setting_string_2"]);
        Console.WriteLine("setting_bool_2 = " + configuration["appSettings_2:setting_bool_2"]);
        Console.WriteLine("setting_int_2 = " + configuration["appSettings_2:setting_int_2"]);
        Console.WriteLine("setting_double_1_2 = " + configuration["appSettings_2:setting_double_1_2"]);
        Console.WriteLine("setting_double_2_2 = " + configuration["appSettings_2:setting_double_2_2"]);

        Console.ReadLine();
    }
}

上記コードを実行すると以下の出力になります。

setting_string_2 = abcdefg2
setting_bool_2 = false
setting_int_2 = 20
setting_double_1_2 = 1.23456
setting_double_2_2 = 5.22E-6

ちなみに、XMLも"Microsoft.Extensions.Configuration.XML"を追加すると読めないことも無いですが、今まで通りの形式だとKey属性が重複してますと出て例外が出て読み込めないためF/WのApp.Configのそのままの転用は難しそうです。