ASP.NET Core で定数をappsettings.jsonに用意して使用する

2020-09-21 | コメント(0)

ASP.NET Core には、Web.configはありません。

ASP.NET Framework では、Web.configのappsettings属性に定数を用意して使用することが多いですが、ASP.NET Core で同等のことをどのように行うかについて、ASP.NET Core を初めて触るときに悩むことの一つだと思います。

説明のため、任意な文字列と数値を仮定して、appsettings.json には下記のように StringKey1、IntegerKey1 というキーで値を追加することとします。

{
  "StringKey1": "任意の文字列",
  "IntegerKey1": 987,
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

サンプル設定の例として記載していますが、ルート位置に設定キーを指定すると、キーが多く増えてきた場合に分かり難くなってきます。
このため、例えば、アプリ寄りの設定値か、インフラ寄りの設定値か、特定のページに対してのものかなど、特定のキーをルートに決めて、階層的になるように纏めて設定することをお勧めします。

appsettings.json の文字列値が、アプリケーションで取得すると文字化けする場合は、appsettings.json のファイルの文字コードが shift-jis になっていることが原因です。UTF-8で保存すると文字化けが直ると思います。

まずは、ASP.NET Core がサポートする依存関係の挿入(DI)の基本の使用方法として、MVCアプリケーションのコントローラーで IConfiguration をDIする場合のコードです。

...
using Microsoft.Extensions.Configuration;

namespace SampleConfigurationMvc.Controllers
{
    public class HomeController : Controller
    {
        private readonly IConfiguration _configuration;

        public HomeController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public IActionResult Index()
        {
            // キー指定して値を取得
            var StringKey1 = _configuration.GetValue<string>("StringKey1");
            var IntegerKey1 = _configuration.GetValue<int>("IntegerKey1");

            // 例として、存在しないキーを指定した場合
            var StringKey2 = _configuration.GetValue<string>("StringKey2");
            var IntegerKey2 = _configuration.GetValue<int>("IntegerKey2");

            return View();
        }
    }
}

この処理の説明としては、コントローラーのコンストラクタで IConfiguration をDIで受け取り、ローカル変数の _configuration として保持させます。

※ IConfigurationを修飾するため、Microsoft.Extensions.Configuration を using します。

アクションメソッド内では、既にコンストラクタ処理は終わっているので、IConfiguration のインスタンス変数からの GetValue<T> メソッドで指定キーの値が取得できるようになります。

このコードの実行結果は以下になります。

ASP.NET Core MVC コントローラーのIConfigurationのDI

StringKey1 は GetValue<string>(..) により文字列値が、IntegerKey1 は GetValue<int>(..) により数値が取得できます。

もし appsettings.json に存在しないキーを取得しようとすると、文字列値は null、数値は 0 となります。
※ StringKey2、IntegerKey2の結果参照。

GetValue<T>では、stringとintの場合に例外は発生しないようです。

コントローラーで IConfiguration をDIすることで目的のことは達成できるのですが、コントローラーが増えるにつれてコンストラクタを修正することが煩雑になってきます。更にモデルやビューを絡めて、IConfiguration のインスタンス変数を引き渡していこうとすると、この煩雑さが広範囲な負担になることに気付きます。

アプリケーションは、IConfiguration のインスタンス変数にアクセス出来れば良いので、個別クラスでstaticな変数にインスタンスを用意できれば、コントローラーからのDIに固執する必要はありません。

ASP.NET Core のMVCプロジェクトのテンプレートでプロジェクト作成したStartup.csを見ると、Startupメソッドで、IConfiguration がDIされていることが判ります。

...
public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }
...

Startupクラスは、アプリケーションが動作する前の初期処理になります。このタイミングは最初の処理になるので、このときにDIされる IConfiguration を、個別クラスのstatic変数に格納してしまえば良いです。

具体的な個別クラスをどこに用意するかは、アプリケーションの自由なので任意ですが、一例として、Startup.cs 内に AppGlobalObject という名前のクラスでstatic変数を用意したコードを記載します。

using ...

namespace SampleConfigurationMvc
{
    public class AppGlobalObject
    {
        public static IConfiguration Configuration { get; set; }
    }

    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            AppGlobalObject.Configuration = configuration;
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
...
...
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
...
...
        }
    }
}

Startupメソッドで、AppGlobalObject.Configuration プロパティに、DIされてきた IConfiguration のインスタンスを代入してしまいます。

AppGlobalObject.Configuration プロパティは static なので、どこからでも参照可能になります。
このため、コントローラー以外でも、モデルやビュー内からも使用できますし、BackgroundWorkerなどの処理からも参照可能になります。

上のコードは、アクサセとして { get; set; } のため、代入もできてしまうのでアプリケーション処理では、代入は行わないようにしてください。参画人数が多いプロジェクトの場合は、より堅牢になるように readonly プロパティになるように工夫したほうが良いかもしれません。

先の、IConfiguration をDIするパターンを修正すると、次のようになります。

...
using Microsoft.Extensions.Configuration;

namespace SampleConfigurationMvc.Controllers
{
    public class HomeController : Controller
    {
        public HomeController()
        {
        }

        public IActionResult Index()
        {
            // キー指定して値を取得
            var StringKey1 = AppGlobalObject.Configuration.GetValue<string>("StringKey1");
            var IntegerKey1 = AppGlobalObject.Configuration.GetValue<int>("IntegerKey1");

            // 例として、存在しないキーを指定した場合
            var StringKey2 = AppGlobalObject.Configuration.GetValue<string>("StringKey2");
            var IntegerKey2 = AppGlobalObject.Configuration.GetValue<int>("IntegerKey2");

            return View();
        }
    }
}

取得結果としては同じです。

ASP.NET Core でststicなIConfiguration変数からの値の取得

先のコードと比べると、コンストラクターでDIするために引数を追加することや、ローカル変数に格納する等の煩雑な処理は必要なくなったので、コードもスッキリします。

IConfigurationを使用する場合では、DIパターンよりも、static変数にIConfigurationを入れてアクセスするほうが断然お薦めです。

カテゴリ:

コメントする

※HTMLタグは使えません

Author

あきちゃん

主に、.NETでWebシステムの設計と開発をしています。
(茨城県在住, 都内勤務)
プロフィール