17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【.NET】設定ファイル(例 appsettings.json)をクラスにマッピングする

Last updated at Posted at 2023-01-28

はじめに

.NET Framework で作成した自社製ライブラリーを、.NET 7 に移植することにした。
.NET Framework では設定ファイルは、App.config (XML 形式)を使用していたが、.NET(旧名 .NET Core)からは、appsettings.json(JSON 形式)が推奨されている。

前回は、コメントに関する記事を書きました。

今回はマッピングについて書いていきます。要はJSONのデシリアライズですね。
この記事はあくまで、IConfiguration を使用することを前提としています。

マッピング

設定ファイルの appsettings.json を用意します。

appsettings.json
{
  "appSettings": {
    "foo": "Bob",
    "bar": 42
  }
}

マッピング用のクラスを用意します。

Settings.cs
public class Settings
{
    public string Foo { get; set; } = "";
    public int Bar { get; set; }
}

設定ファイルの appsettings.json を読み込みます。

Program.cs
var config = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", false)
            .Build()

Getが見つからない

Program.cs
var settings = config.GetSection("appSettings").Get<Settings>();

ネット上でマッピングするのに、Get<T>() や Bind などを使用した例が記載されているがインテリセンスに出てこないのである。よく見れば参考した記事はどれも ASP.NET Core の記事ばかり。コンソールやクラスライブラリー等では使えないの?

「C# Configuration get not found」って英語で検索したトップ記事に回答があった。

Install the NuGet package:
Microsoft.Extensions.Configuration.Binder
https://stackoverflow.com/questions/36694099/iconfiguration-does-not-contain-a-definition-for-get

image.png

結果

インストールすることで、Get<T>() や Bind が使用できるようになった。
Setting クラスにマッピングできています。

image.png

Get() を使用

Program.cs
var settings = config.GetSection("appSettings").Get<Settings>();

Bind を使用

Program.cs
var settings = new Settings();
config.Bind("appSettings", settings);

マッピング(属性指定)

下記サイトにあるようにオブジェクトをJSONにシリアライズする際には、DataMember属性を付与し、Nameに JSONのキーを指定することができた。またSystem.Text.Jsonの場合なら、JsonPropertyName属性となる。

DataMember属性やJsonPropertyName属性を指定しても駄目だったので、 Configurationで同じことが出来ないか検索してみた。

ConfigurationKeyNameAttribute Classが、.NET 6 からサポートされ、ConfigurationKeyName が使用できるようになりました。

IgnoreDataMember属性 は見当たらないので、無視は出来なそう。

[ConfigurationKeyName(Name = "Named_Property")]
public string NamedProperty { get; set; }

サンプルソース

複数のデータベースを共通化するクラスを作成するため、接続情報としてdatabase.jsonを設定した。

database.json
{
  "dbSettings":{
    "dbType":"SQLServer",
    "connection":[
        {
            // 接続名
            "@name":"PostgreSQL",
            // 接続名
            "connectionString":"Server=localhost;Port=5432;User Id=test;Password=P@ssw0rd;Database=test;CommandTimeout=600;"
        },
        {
            // 接続名
            "@name":"SQLServer",
            // 接続名
            "connectionString":"Data Source=localhost;Initial Catalog=ServerWatch;User ID=Test;Password=P@ssw0rd;TrustServerCertificate=True;"
        },
        {
            // 接続名
            "@name":"Oracle",
            // 接続名
            "connectionString":"Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=TEST.DB))); User Id=test; Password=P@ssw0rd"
        }
    ]
  }
}

プロパティ名とキー名が不一致でも、ConfigurationKeyName 属性を使用してマッピングするキーを指定できます。

DBSettingData.cs
public class DBSettingData
{
    public string DBType { get; set; } = "";
    [ConfigurationKeyName("connection")]
    public DbConnections DBConnections { get; set; } = new DbConnections();
}

public class DbConnections : List<DbConnection>
{
    private int IndexOf(string name)
    {
        for (int i = 0; i < Count; i++)
        {
            DbConnection con = base[i];
            if (con.Name == name)
                return i;
        }
        return -1;
    }
    public DbConnection this[string name]
    {
        get
        {
            foreach (DbConnection con in this)
            {
                if (con.Name == name)
                    return con;
            }
            return null;
        }
        set
        {
            int i = IndexOf(name);
            if (i == -1)
                Add(value);
            else
                base[i] = value;
        }
    }
}

public class DbConnection
{
    [ConfigurationKeyName("@name")]
    public string Name { get; set; } = "";
    public string ConnectionString { get; set; } = "";
}

データベース設定情報 database.json を読み込みます。
設定情報のDBType:SQLServerなので、ConnectionStringには、SQLServerの接続文字列がセットされます。

DataBaseInfo.cs
using Microsoft.Extensions.Configuration;

public class DatabaseInfo
{
    // データベース種類定義
    public const string DB_TYPE_POSTGRESQL = "PostgreSQL";
    public const string DB_TYPE_SQLSERVERL = "SQLServer";
    public const string DB_TYPE_ORACLE = "Oracle";
    public const string DB_INFO_JSON_FILENAME = "database.json";
    public const string DB_INFO_DEFAULT_SECTION = "dbSettings";
    // データベースの種類
    public string DBType { get; set; } = "";
    // データベースの接続情報
    public string ConnectionString { get; set; }
    /// <summary>
    /// コンストラクタ
    /// </summary>
    public DatabaseInfo(string path)
    {
        SetConnectionInfo(path,  DB_INFO_DEFAULT_SECTION);
    }
    /// <summary>
    /// DB情報をセットします。
    /// </summary>
    /// <param name="path">データベース接続情報パス名</param>
    /// <param name="section">セクション名</param>
    public void SetConnectionInfo(string path, string section)
    {
        try
        {
            var dbs = new DBSettingData();
            var config = new ConfigurationBuilder()
                            .AddJsonFile(path)
                            .Build();

            config.Bind(section, dbs);
            // データベースの種類セット
            DBType = dbs.DBType;
            // 接続文字列の情報セット
            ConnectionString = dbs.DBConnections[DBType].ConnectionString;
        }
        catch
        {
            throw;
        }
    }
}

最後に

まだここらへんに関して検索する限りだと、日本では情報がなかなか見当たらないですね。
なので、検索キーを英語にして検索するなど工夫する必要があります。

ConfigurationKeyName など一旦キーワードが見つかれば情報が出て来たりしますが、自分自身で発信していくしかないですね。

IConfigurationはJSON以外にも環境変数やコマンドラインパラメータで指定した設定情報などが読み込める。

単にJSONのみならSystem.Text.Jsonを使えばいい気もする。属性で色々出来そうだし。

17
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?