C#、ASP.NET、TypeScript、AngularJS を中心にプログラミングに関した話題を諸々。
by @jsakamoto
検索
リンク
北海道のITコミュニティ - CLR/H 無聊を託つ
タグ
カテゴリ
最新の記事
はじめての C# からの S..
at 2018-12-09 00:00
npm パッケージのバージョ..
at 2018-11-09 22:28
.NET Framework..
at 2018-10-28 00:59
ASP.NET Core の..
at 2018-09-28 23:29
[解決] スリープからの復帰..
at 2018-08-28 18:37
最新のコメント
すみません、記事書きかけ..
by developer-adjust at 22:36
続きはないんですか?
by hanamo at 13:03
助かりました。ありがとう..
by あああ at 21:32
いえす、F#! F#! :)
by developer-adjust at 21:46
F#はAzure Not..
by 幻のK泉さん at 18:37
> 今、Setcronj..
by developer-adjust at 08:25
今、Setcronjob..
by Kibe at 03:23
Jichym 改め yi..
by yi at 23:00
バッチファイル(.bat..
by Jichym at 01:26
なるほど、そこにテコ入れ..
by developer-adjust at 21:25
記事ランキング
最新のトラックバック
Web API における..
from 松崎 剛 Blog
[Other]Code2..
from KatsuYuzuの日記
Developer @ ..
from .NET Clips
asp.netでrail..
from 4丁目より
F#でASP.NET M..
from ナオキにASP.NET(仮)
[B!] これはいい h..
from Twitter Mirror
[報告] Microso..
from .NET Clips
Developer @ ..
from .NET Clips
[F#]F# でブログア..
from 予定は未定Blog版
ASP.NET MVC ..
from ナオキにASP.NET(仮)
以前の記事
2018年 12月
2018年 11月
2018年 10月
2018年 09月
2018年 08月
2018年 07月
2018年 06月
2018年 05月
2018年 04月
2018年 03月
2018年 02月
2018年 01月
2017年 12月
2017年 11月
2017年 10月
2017年 09月
2017年 08月
2017年 07月
2017年 06月
2017年 05月
2017年 04月
2017年 02月
2017年 01月
2016年 12月
2016年 11月
2016年 10月
2016年 09月
2016年 08月
2016年 07月
2016年 06月
2016年 05月
2016年 04月
2016年 03月
2016年 02月
2016年 01月
2015年 12月
2015年 11月
2015年 10月
2015年 09月
2015年 08月
2015年 07月
2015年 05月
2015年 04月
2015年 03月
2015年 02月
2015年 01月
2014年 12月
2014年 11月
2014年 10月
2014年 09月
2014年 08月
2014年 06月
2014年 04月
2014年 03月
2014年 02月
2014年 01月
2013年 12月
2013年 10月
2013年 09月
2013年 08月
2013年 07月
2013年 06月
2013年 05月
2013年 04月
2013年 03月
2013年 02月
2013年 01月
2012年 12月
2012年 11月
2012年 10月
2012年 09月
2012年 08月
2012年 07月
2012年 06月
2012年 05月
2012年 04月
2012年 03月
2012年 02月
2012年 01月
2011年 12月
2011年 11月
2011年 10月
2011年 09月
2011年 08月
2011年 07月
2011年 06月
2011年 05月
2011年 04月
2011年 03月
2011年 02月
2011年 01月
2010年 12月
2010年 11月
2010年 10月
2010年 09月
2010年 08月
2010年 07月
2010年 06月
2010年 05月
2010年 04月
2010年 03月
2010年 02月
2010年 01月
2009年 12月
2009年 10月
2009年 09月
2009年 07月
2009年 06月
2009年 05月
2009年 04月
2009年 03月
2009年 02月
2009年 01月
2008年 12月
2008年 11月
2008年 10月
2008年 09月
2008年 08月
2008年 07月
2008年 06月
2008年 05月
2008年 04月
2008年 03月
2008年 02月
2008年 01月
2007年 12月
2007年 11月
2007年 04月
2007年 03月
2007年 02月
2007年 01月
2006年 11月
2006年 10月
2006年 09月
2006年 08月
2006年 07月
ファン
ブログジャンル
画像一覧
2018年 11月 09日

npm パッケージのバージョンを上げてたら webpack 実行時に _ValidationError2.default 例外が発生

JavaScript を webpack を使ってモジュールバンドルする、そんな SPA な Web アプリ開発の話。

個人的には早く Blazor に移行したくてたまらない今日この頃であるが、仮に Blazor が公式リリースされたとしても、これまで開発した webpack な JavaScript 製 SPA の保守は必要である。

さて、今回、そのような事情から、過去に作ったプロダクトの保守が発生した。

折角の保守の機会なので、60本ほど参照している npm パッケージを確認し、せめてパッチバージョンくらいは更新しておこう、とちまちま参照 npm パッケージのバージョンを、場合によってはマイナーバージョンも含めて手作業で上げていった。
(※ ncu は知ってるけど、諸事情により今回は出番なし。)

さてこんな感じかなー、と落ち着いたところで、webpack を実行してみたところ、下記の例外が出るようになってしまった。
...\node_modules\schema-utils\dist\validateOptions.js:42
throw new _ValidationError2.default(ajv.errors, name);
^

せっかくのエラー詳細がわからない

コンソール出力を読むに、schema-utils モジュールで JSON スキーマに基づく入力 JSON の検証で、検証エラーが発生したっぽい。

ということは、おそらくは、webpack.config.js の記載内容のどこかに誤りがあるのだろう、というところまでは察しがついた。

しかしここまでの情報では、いったい webpack.config.js 中のどこでどんな問題で JSON スキーマ検証エラーになったのか、見当がつかない。

いちおう、ネットで検索もしてはみたけれども、まぁ、いろいろヒットするにはするのだが(下記は一例)、


いかんせん、このエラーを引き起こす原因は、ようするに JSON の書き損じなので、それこそシチュエーションは十人十色。
ネット検索の結果では、自分のケースを解決できそうにもない。

上記コンソール出力を見るに、せっかく "ajv.errors" や "name" といった有益そうな情報を例外オブジェクトにまとめて throw してくれているのに、その内容が見られないことには如何ともしがたい。

webpack の機能(例えばコマンドラインスイッチなど?)で例外内容を見る事ってできるんでしょうか。

console.log で出力するように書き換えてしまえ!

正攻法はわからず仕舞いだったが、幸い、上記コンソール出力には、大変有り難いことに、例外を発射している箇所の JavaScript ファイル名と行番号が書いてある。

そこで、この JavaScript ファイル ― .\node_modules\schema-utils\dist\validateOptions.js ― の該当箇所に console.log() を書き足して、エラーの内容、すなわち "ajv.errors" と "name" の内容をコンソール出力するようにした。
d0079457_22161070.png
これでもういちど webpack を実行すると、エラーの詳細がコンソールに出力された!
d0079457_22165075.png
これでようやくわかったのは、

  • この検証エラーは UglifyJs Plugin に関する JSON で発生していること、
  • そして JSON 中、"parallel" プロパティの指定は boolean か interger のいずれかである必要があるのに、それに違反している

ということだ。

改めて webpack.config.js 中の UglifyJs プラグインを構成しているところを確認してみる。
new UglifyJSPlugin({ parallel: { cache: true, workers: 2 } })
たしかに、parallel プロパティに、boolean ないしは integer ではなく、オブジェクトを渡していた。
かつてはこの設定方式でよかったのだろうけれども、新しいバージョンでは不可となったということであろう。

自分は Windows OS 上で Visual Studio IDE を使って開発をしているのだが、幸い、Visual Studio のエディタの支援によって、現在バージョンにおけるオプション指定をガイドしてもらうことができた。
d0079457_22172414.png
ということで、 UglifyJs プラグインの構成を下記に更新。
new UglifyJSPlugin({ parallel: true, cache: true })
これで再び webpack を実行すると、今度は無事成功した。
解決!

# by developer-adjust | 2018-11-09 22:28 | その他IT系 | Comments(0)
2018年 10月 28日

.NET Framework 上での xUnit 単体テストを SDK スタイルのプロジェクト形式で作る

xUnit 単体テストプロジェクトも SDK スタイルでやりたい!

Windows OS 上で Visual Studio 2017 を使ってのプログラム開発における、.NET Core ではなく .NET Framework 用の単体テストプロジェクトの話。

C# + .NET Framework 用の単体テストプロジェクトを作ると、そのプロジェクトファイルの形式は、新しい "SDK スタイル" と呼ばれる形式ではなく、旧来からのプロジェクト形式となる。

もっとも、単体テストのプロジェクト形式が従来形式だからといって、そんなに困ることもない。

しかし最近、xUnit を使った単体テストプロジェクトにおける NuGet パッケージ参照で躓いてしまった。

というのも、従来形式のプロジェクトだと、基本的にソリューションファイルからの相対位置で、packages サブフォルダに参照パッケージがダウンロードされる。
そのせいで、ちょっと別のフォルダ階層のソリューションから同プロジェクトを参照すると、".dll が見つからない!" といったビルドエラーになってしまったのだ。

SDK スタイルのプロジェクト形式だと、NuGet パッケージ参照の方式が変わるので、このようなトラブルはなくなる。

そこで、この xUnit 単体テストプロジェクトを、SDK スタイルのプロジェクト形式に変更してみた。

SDK スタイル形式で xUnit 単体テストプロジェクトを作る

変更といっても、.csporj ファイルを書き換えると、手落ちがあっては後々面倒である。
そこで改めて新規プロジェクト作成から進めてみた。

Visual Studio を起動し、プロジェクトの新規作成から、(今回対象のプロジェクトは、.NET Core ではなく .NET Framework である必要があるのだが、まずは)「.NET Core」のカテゴリを選択、xUnit の単体テストプロジェクトを作成する。
d0079457_00252250.png
今回対象のプロジェクトは、.NET Core ではなく .NET Framework である必要があるのに、あえて「.NET Core」用の単体テストプロジェクトを作ったのは、SDK スタイルの C# + xUnit な単体テストプロジェクトファイルを作成するのにいちばん近道だったからだ。

そして続けて、できあがった xUnit 単体テストプロジェクトファイルを編集し、対象フレームワークを .NET Core から .NET Framework に書き換える。

今回の .NET Framework の対象バージョンは 4.5 だったので、.csproj ファイルには "net45" と記した。
d0079457_00252265.png
これで、対象フレームワークは .NET Framework 4.5 としつつ、プロジェクト形式が SDK スタイルの、 C# + xUnit 単体テストプロジェクトが出来上がった。

上手くいったと思ったのだが...

早速テストコードを移植しビルドしてみると、当然のことながらビルドは成功し、Visual Studio のテストエクスプローラにもテストが検出されて表示された。
d0079457_00252204.png
ここまでは順風満帆。

では単体テストを実行してみると...



あれ?

テストエクスプローラの表示上、各テストがいずれも「未実行」のアイコンのまま。

Visual Studio の出力ウィンドウをよく見てみると、
d0079457_00252238.png
xunit.execution.desktop.dll がないので単体テストを実行できません、というではないか。


たしかに、単体テストプロジェクトの出力フォルダを見てみると、言われた xunit.execution.desktop.dll ファイルは存在しない。
(.NET Core プロジェクトではなく .NET Framework のプロジェクトなので、GAC に存在しない必要なDLLファイルは出力フォルダに出現する)
d0079457_00252208.png

.NET Framework 4.5.2 なら OK!?

どうしてこういう事態になるのか、あまり深く考えずにとりあえずはとばかりにネットで検索してみた。

そうしたところ、xUnit のリリースノートに答えが。


.NET Framework のバージョン 4 および 4.5.1 は公式サポート期間を過ぎたので、4.5 ではなく、4.5.2 に引き上げろ、とのこと。

公式サポート期間、なるほど、そうでした。

自分のこのケースでは、たまたま古い内製ライブラリの保守の関係で、当時、.NET Framework 4.5 を対象にしていたので単体テストプロジェクトも .NET Framework 4.5 を対象に考えていて、こうなってしまったのであった。

ということで、単体テストプロジェクトの対象 .NET Framework のバージョンを、4.5 から、4.5.2 に引き上げてみた。

その上でリビルドし、Visual Studio のテストエクスプローラからテスト実行したところ、今度は期待どおりに実行されたのであった。
d0079457_00252231.png

ちなみに、.NET Framework のバージョンを 4.5.2 に引き上げたプロジェクトでの出力フォルダを見てみると、ちゃんと xunit.execution.desktop.dll ファイルが配置されていた。
d0079457_00252247.png


まとめ

以上、とりあえず、

  • (.NET Core ではなく) .NET Framework + C# + xUnit な単体テストプロジェクトを、SDK スタイルのプロジェクト形式で Visual Studio 上で開発・実行することは可能
  • 但し、対象 .NET Framework のバージョンが 4.5 だと期待どおりに動作しないので、4.5.2 に引き上げる必要がある

ということがわかった。


# by developer-adjust | 2018-10-28 00:59 | Visual Studio | Comments(0)
2018年 09月 28日

ASP.NET Core のアプリケーション構成を上書きするいろいろ - 特に環境変数とコレクション

ASP.NET Core アプリのアプリケーション構成

ASP.NET Core アプリは、標準のプロジェクトテンプレートで作成すると、プロジェクトのフォルダにある appSettings.json というファイルを読みこんで、アプリケーション構成として使用するようにできている。

この appSettings.json にアプリケーション固有の半固定パラメータなどの設定値を JSON 形式で記述しておき、アプリ中からその設定値を読み取って利用する、というものだ。
詳しくは下記を参照するとよいだろう。

例えば下記のような appSettings.json を用意したとして、
{
"SiteSettings": {
"Title": "Hello World",
"TimeZone": {
"Name": "Tokyo Standard Time",
"Offset": 9
},
"Tags": [
{ "Text": "Foo", "Priority": 0.7 },
{ "Text": "Bar", "Priority": 0.3 }
]
}
}
ASP.NET Core アプリの実装コード (今回は C#) で、下記のように、上記 appSettings.json の JSON 構造にマッピングされるクラスを用意して、
public class SiteSettings {
public string Title { get; set; }

public TimeZoneSettings TimeZone { get; set; }

public class TimeZoneSettings {
public string Name { get; set; }
public int Offset { get; set; }
}

public TagSettings[] Tags { get; set; }

public class TagSettings {
public string Text { get; set; }
public double Priority { get; set; }
}
}
ASP.NET Core アプリの Startup クラスにて、下記のように、appSettings.json ファイル中の SiteSettings ノード以下を DI コンテナへサービス登録することで、
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public void ConfigureServices(IServiceCollection services)
{
services.Configure<SiteSettings>(Configuration.GetSection("SiteSettings"));
...
`IOptions<SiteSettings>` 型のインスタンスを DI 機構によって入手できるようになる。

この `IOptions<SiteSettings>` オブジェクトの各プロパティを参照すると、appSettings.json の記載内容が SiteSettings オブジェクトにマッピングされて読み取られ、参照可能となっている寸法だ。
// 変数 settings は、DI 機構から入手した IOptions<SiteSettings> オブジェクトへの参照
settings.Value.Title; // <- "Hello World"
settings.Value.TimeZone.Name; // <- "Tokyo Standard Time"
settings.Value.TimeZone.Offset; // <- 9
settings.Value.Tags[0].Text; // <- "Foo"
settings.Value.Tags[1].Text; // <- "Bar"

アプリケーション構成の "上書き"

この appSettings.json に記載されている設定値だが、いくつかの方法で "上書き" が可能だ。

ひとつは appSettings.Develop.json に記述する方法。
開発環境での実行時は、appSettings.json の設定値に対して、appSettings.Develop.json に記述した設定値で上書きされたように、アプリ側では設定値を読み取るようにできているのだ。

この仕組みにより、appSettings.json には既定値を、appSettings.Develop.json には各開発者固有の環境依存の設定値など(例えばデータベースの接続先設定値とか)を記載しておいたりして、アプリの動作を調整できる。

例えば先の例だと、appSettings.Develop.json に以下のように記述しておくと、
{
"SiteSettings": {
"TimeZone": {
"Name": "Asia/Tokyo",
}
}
}
アプリ側の読み取り結果は下記のとおりとなる。
settings.Value.Title; // <- "Hello World"
settings.Value.TimeZone.Name; // <- "Asia/Tokyo" ... 上書きされた!
settings.Value.TimeZone.Offset; // <- 9
settings.Value.Tags[0].Text; // <- "Foo"
settings.Value.Tags[1].Text; // <- "Bar"
なお、appSettings.Develop.json の "Develop" のファイル名部分は、実は環境変数 ASPNETCORE_ENVIRONMENT の値である。
なので、環境変数 ASPNETCORE_ENVIRONMENT に "FooBar" を設定すれば、appSettings.FooBar.json が上書き用に読み込まれる。

アプリケーション構成のセクション名は英字の大小が区別されない

話は逸れるが、面白い(?)ことに、appSettings.Develop.json で appSettings.json の設定値を上書きする際、セクション名 (ノード名、プロパティ名) の英字の大文字と小文字は一致しなくても構わない。
アプリケーション構成のセクション名は Case Insensitive として動作するのだ。

なので、appSettings.json に、英字の大小違いの同一セクションを設けると(例えば下記)、JSON としては間違いではないのだが、その ASP.NET Core アプリは起動時にクラッシュしてしまう。
{
"SiteSettings": {
"title": "hello world", // <- セクション名の先頭が文字
"Title": "Hello World", // <- セクション名の先頭が文字
IIS 経由で実行した場合は
「HTTP Error 502.5 - Process Failure - The application process failed to start」
として現れるし、「dotnet run」で実行すると、
「Unhandled Exception: System.FormatException: A duplicate key 'SiteSettings:Title' was found.」
というように、重複キー発生である例外メッセージがコンソール出力から読み取れる。
d0079457_23131528.png

環境変数で "上書き"

アプリケーション構成を上書きするもうひとつの方法は、環境変数で "上書き" する方法である。

appSettings.json 中の各セクション (ノード、プロパティ) 名を、コロン (:) 区切りで連結した名前で環境変数を定義すると、その環境変数の値がアプリケーション構成として読み取れるのだ。
言い換えると、C# や JavaScript 上、ドット (.) で区切るところをコロン区切りに置き換えた名前、とも言える。

先の例でいくと、例えば環境変数 "SiteSettings:TimeZone:Offset" に "8" と設定してから実行すると、アプリでの読み取り結果は下記のとおりとなる。
settings.Value.Title; // <- "Hello World"
settings.Value.TimeZone.Name; // <- "Tokyo Standard Time"
settings.Value.TimeZone.Offset; // <- 8 ... 9 から 8 に上書きされた!
settings.Value.Tags[0].Text; // <- "Foo"
settings.Value.Tags[1].Text; // <- "Bar"
Windows OS 上で Visual Studio を用いて開発・実行している場合は、Visual Studio の画面上、プロジェクトのプロパティ画面から環境変数を設定することもできる。
d0079457_23144057.png
このやり方だと、環境変数の設定を変更して保存 (Ctrl +S) すると、Visual Studio が自動で ASP.NET Core アプリのプロセスを再起動してくれ、アプリケーション構成が再読み取りされて、設定内容が即反映されるのだ。

appSettings.json 及び appSettings.Develop.json を編集・保存した場合は、そのようなプロセス再起動をはじめ、自動でアプリケーション構成を再読み取りされることはないようである。
(どこかで、appSettings.Develop.json が変更されたら再読み取りするオプション指定を見かけたような気もするのだが。)

ちなみに、こうして Visual Studio 上から設定した環境変数設定は、プロジェクトのフォルダ以下、Properties フォルダ内の launchSettings.json 内に書き込まれる。

「dotnet run」で実行する際も、この launchSettings.json の内容は読み取られて使われる。
なので、launchSettings.json に環境変数を設定しておいて「dotnet run」で実行すると、その環境変数設定が反映されて実行される。
ご参考までに。

また、これも至極当然のことではあるが、こうして環境変数で上書きする際も、セクション名 (環境変数名) の英字の大小は区別されない。

Microsoft Azure の App Service 設定での "上書き"


実は、Microsoft Azure の App Service 上に Web アプリを配置したときに、Azure ポータルから「アプリケーション構成」で設定する値も、アプリ側には環境変数として現れる。
なので、この仕組みで、ASP.NET Core アプリのアプリケーション構成を Azure ポータルから上書き設定することができるのだ。

その際のセクション名の指定方法は、上記のとおりコロン区切りでセクション名を連結した名前を、Azure ポータル「アプリケーション構成」の欄の "APP SETTING NAME" のところに指定してやれば良い。
d0079457_23263924.png


"上書き" というよりは "合成" と言ったほうがイメージあってる?


これら "上書き" の動作だが、優先順位としては次のとおり。

環境変数 > appSettings.Develop.json > appSettings.json

上記3者で同じセクション名で異なる値をそれぞれ設定していた場合、環境変数による設定が勝つ。

また、"上書き" とは言ったが、appSettings.json 内に記述のないセクション名のアプリケーション構成を、環境変数で設定してあれば、アプリ側ではちゃんと読み取れる。

例えば appSettings.json に SiteSettings.Title がなくても、
"SiteSettings": {
"TimeZone": { // <- "Title" プロパティがない!
...
環境変数 "SiteSettings:Title" に "HELLO!" が設定されていれば、アプリ側ではちゃんと読み取れる。
settings.Value.Title; // <- "HELLO!" ... 環境変数での設定が見えている!
なお、上記のような例を見ると、appSettings.json に存在しないセクションなので、存在しないものに対して "上書き" という言い方には違和感を覚えるかもしれない。
上書きというよりかは、Key-Value の辞書のツリーを "合成" (マージ) していくようなイメージのほうが理解しやすいかもしれない。

よくよく考えたら、環境変数を読むのに使えたり。

ここまでを振り返ってよくよく突き詰めて考えてくと、実は ASP.NET Core のアプリケーション構成の仕組みで、環境変数がまるっと取得できてしまったりもするのだ。

ここまで紹介してきた例では、Startup にて、"Configuration.GetSection("SiteSettings")" と設定していたので、すべての環境変数は見えず、"SiteSettings:~" で始まる名前の環境変数だけ見えていた。

これを改め、単に "Configuration" オブジェクトそのものを渡してバインドすれば、すべての環境変数値がバインド可能だ。

また、ASP.NET Core アプリケーション構成の仕組みは、必ずしも静的型付けしなくては使えないわけではなく、Configuration オブジェクトを参照し、その GetValue などのメソッドを使って、文字列でセクション名 (= 環境変数名) を指定して取得することもできる (下記など参考に)。
本来の用途ではないが、ASP.NET Core のアプリケーション構成の仕組みを介して、プロセスの環境変数をすべて参照することも可能だ。

ところで、コレクションって何にバインドできる?

ところで、今回の例にある、"Tags" セクションは、JSONN 上、配列になっており、これのバインド先の SiteSettings クラスでも配列としている。
public class SiteSettings {
...
public TagSettings[] Tags ... // <- TagSettings 型の "配列"
...
試したところ、実はここ、配列じゃなくても大丈夫だった。
"List<T>" でも "IEnumerable<T>" でも "ICollection<T>" でもバインドできた。
public class SiteSettings {
...
public IEnumerable<TagSettings> Tags ... // <- これでも OK!
...
果たして "T[]"、"List<T>"、"IEnumerable<T>"、"ICollection<T>"、etc. のいずれでバインドするのが最適なのか、自分にははっきりとは判断つきかねる。

ただ、どちらかといえばいちばん書き換えできなさそうな "IEnumerable<T>" がいいのかなぁ、と漠然と考えている。


環境変数からコレクションの設定を上書きするには?

さて今回の例の "Tags" セクション内の配列構成を、環境変数で上書きするには、どのような変数名を指定すればよいのだろう?

最初は、"SiteSettings:Tags[0]:Text" というような、C# や JavaScript などでよくあるインデクサ表記を環境変数名とすることで上書きできるのかと考えた。
が、試したところこれは間違い。

正解は "SiteSettings:Tags:0:Text" だ。

これは "JavaScrit 的な考え方" に慣れてるとわかりやすいと思う。
すなわち、配列の要素を、例えば0番目の要素であれば「Tags オブジェクトの、"0" という名前のプロパティ」というように捉えるのだ。

今回の例の、上書き前のオリジナルの appSettings.json の構成内容だと、Tags プロパティの内容は下記のとおりとなっている。
settings.Value.Tags[0].Text; // <- "Foo"
settings.Value.Tags[0].Priority; // <- 0.7
settings.Value.Tags[1].Text; // <- "Bar"
settings.Value.Tags[1].Priority; // <- 0.3
ここで環境変数 "SiteSettings:Tags:1:Text" に "Hoge" を設定すると、下記のとおり上書きされる。
settings.Value.Tags[0].Text; // <- "Foo"
settings.Value.Tags[0].Priority; // <- 0.7
settings.Value.Tags[1].Text; // <- "Hoge" ... "Bar" から上書きされた!
settings.Value.Tags[1].Priority; // <- 0.3 ... ここはそのまま!

上書き前の配列要素数を超えたら...?


さて、では今回の例において、環境変数 "SiteSettings:Tags:999:Text" に "Hoge" を設定したらどうなるのか!?

アプリ側で読み取った結果はこうなった。
settings.Value.Tags[0].Text; // <- "Foo"
settings.Value.Tags[0].Priority; // <- 0.7
settings.Value.Tags[1].Text; // <- "Bar"
settings.Value.Tags[1].Priority; // <- 0.3

// Tags[2] が増えた!
settings.Value.Tags[2].Text; // <- "Hoge"
settings.Value.Tags[2].Priority; // <- 0.0
一瞬戸惑ってしまったが、改めて JavaScript 脳になって考えてみると、何のことはない、環境変数名の "999" は「配列の添え字」ではなく、プロパティ名なのだ。

どうやら、ASP.NET Core のアプリケーション構成の仕組みは、バインド先の型がコレクションである場合、バインド元の値の "プロパティ" を列挙して、その値を順繰り、バインド先のコレクションの要素に編成しているようである。

配列、じゃなくて、結局は Key-Value の辞書である

なので、数字だけじゃなくて、任意の識別子を当てはめられる。

例えば環境変数名を、"SiteSettings:Tags:999:Text" ではなく、"SiteSettings:Tags:FizzBuzz:Text" としても、結果は同じになるのだ。

また、環境変数からの上書きというのではなく、appSettings.json の記述そのものを辞書形式で記述することもできる。
"SiteSettings": {
...
"Tags": [
{ "Text": "Foo", "Priority": 0.7 },
{ "Text": "Bar", "Priority": 0.3 }
]
...
は、アプリケーション構成的観点では以下のように記述してるのと同義と言える。
実際、アプリでの読み取り結果も変らなかった。
"SiteSettings": {
...
"Tags": {
"0": { "Text": "Foo", "Priority": 0.7 },
"1": { "Text": "Bar", "Priority": 0.3 }
}
...
さらには、プロパティ名 (Key) は数字である必要すらない。
下記でも TagSetting[] にバインドされ、読み取り結果は変わりない。
"SiteSettings": {
...
"Tags": {
"Alpha": { "Text": "Foo", "Priority": 0.7 },
"Omega": { "Text": "Bar", "Priority": 0.3 }
}
...
ちなみに、上記のような感じで Key-Value 辞書オブジェクトをコレクションにバインドした場合、その要素の追加順序は、プロパティ名 (Key) のオーダーとなるようだ。

削除はできなさそう

なお、このような仕掛けであるようなので、appSettings.json で設定した配列構成要素を、appSettings.Develop.json や環境変数から "削除" することはできなさそうだ。

例えば今回の例において、appSettings.Develop.json を以下のとおり記述し、Tags の設定内容を要素数 0 件に潰そうとしたとする。
"SiteSettings": {
...
"Tags": [] // オリジナルの Tags 構成値を0件にしてやる!
...
しかしこれは意図したとおりには動作しない。

配列ではなく、"0" や "1" といった配列序数を名前としたプロパティを持つオブジェクトを "上書き" するのだ、と JavaScript 脳で考える必要がある。

JavaScript で言うならば、オリジナルの Tags オブジェクト に対し、空のオブジェクトで Object.assign するようなものだ。
var tags = {"0":{...}, "1":{...}};
var tagsDevlop = {}; // "Tags":[] は空オブジェクトと同義

// 空オブジェクトを assign しても、tags は何の変化もなし!
Object.assign(tags, tagsDevelop);
結果として、上記 appSettings.Develop.json は、何の効果ももたらさないこととなる。

そう、JavaScript の Object.assign を知っているならば、ASP.NET Core アプリケーション構成の "上書き" の仕組みは、Object.assign であると考えると間違いがないだろう。

まとめ

以上、ASP.NET Core のアプリケーション構成の上書き (というか、"合成") の振る舞いについて色々試した結果となる。

ざっくりおさらいすると下記のとおり。

  • 英字の大文字・小文字は区別されない。
  • appSettings.Develope.json より環境変数のほうが勝つ。
  • 環境変数ではセクション名をコロンで区切って設定。
  • Visual Studio での環境変数設定は Properties\launchSettings.json ファイルに保存される。
  • コレクションのバインド先は "T[]", "List<T>", "IEnumerable<T>", "ICollection<T>" のいずれでも OK。
  • 環境変数でコレクションの要素を上書きするには、序数をプロパティ名として設定。
  • コレクションもその正体は、"0" や "1" といった序数をプロパティ名とした JavaScript オブジェクト (辞書) であるだけ。
  • なので、序数じゃない任意の識別子も指定できちゃう - その場合、プロパティ名 (Key) のオーダーでコレクションが編成される。
  • 結局、JavaScript の Object.assign() で重ね書きしてる感じ。
  • なので、appsettings.json に設定済みの要素を、削除することはできないと思われる。

あと、最後になってしまったが補足しておくと、ここまでのアプリケーション構成の仕組みは ASP.NET Core アプリに限らず、Microsoft.Extensions.Options でアプリケーション構成を扱う .NET アプリ全てに適用される。

今回の投稿はかなりの大作となってしまった。
これでアプリケーション構成の "上書き" で迷うことはなくなった...と思いたい。


# by developer-adjust | 2018-09-28 23:29 | .NET | Comments(0)
2018年 08月 28日

[解決] スリープからの復帰後、Surface Pro (第5世代) のタイプカバーから文字が打てなくなる


最近、Surface Pro (第5世代) (US配列 Type Cover 込み) を入手、使い始めるようになった。

仕事上、デスクでの作業は外部モニタ + Apple Wireless Keyboard (Bluetooth 接続) をつないで、据え置きで業務を行なっている。

出張時に、Surface Pro 本体と Type Cover だけ持ち出して出かける格好だ。

ところが、入手そうそうトラブルに遭遇してしまった。

本ブログ記事のタイトルのとおり、スリープから復帰後、タイプカバーから文字が打てない状態となってしまうのだ。

再起動以外、復旧しない...

いろいろ試したが、いちどこの現象が発生すると、再起動する以外、復旧しないようであった。

タイプカバーの脱着や、デバイスマネージャからの「Surface Type Cover Filter Device」の削除からの入れ直しも効果無し。

とはいえ、再起動すれば確実に復旧はする。

でも、ちょっと不思議な不具合...

どうしたものかと、いろいろいじってはみたのだが、解決には至らない。

だが、そうやっていじっている内に、この不具合の詳細が見えてきた。

まず、Type Cover それ自体がデバイスとして機能しなくなるわけではなかった。

Type Cover 上のタッチパッドでマウスカーソルは動かしたり、クリックしたりすることは大丈夫なのだ。

さらに加えて、ディスプレイの輝度変更や音量変更などのファンクションキーも動作したのだ。

それ以外の、カーソルキーや文字キー、Caps ロックキーに限って、これらを押しても何の反応も示さない、という挙動なのである。

さらにこの現象発生後、Bluetooth 接続の Apple Wireless Keyboard でも、文字キーに反応しなくなってしまった。

Type Cover のみならず、である。

キーボード入力にかかわるソフトウェアの問題?

ここまできて、これはもしかして、キーボード入力にかかわるソフトウェアが、何か互換性の問題を引き起こしているのでは、と思い至った。

ということで、まずはこの Surface Pro にインストールした、キーボード入力に関わりそうなソフトウェアを思い出しつつ挙げてみた。

- Mouse without Board
- Apple Wireless Keyboard Driver (WinA1314)
- ATOK Passport
- TeamViewer 13 Business

次に、これらを順にアンインストールしてみて、当不具合が解消されるか様子を見てみることにした。

犯人がわかった!

その結果、上記リストの 2つ目、Apple Wireless Keyboard Driver をアンインストールしたところ、嬉しいことにこの不具合現象が解消された。

今にして思えば、文字キー入力を受け付けなくなる現象が、Type Cover のみならず、Apple Wireless Keyboard でも同時発生していた時点で、最有力候補として疑うべきだったかもしれない(まぁ、後知恵バイアスではあるが)。

ということで、ひとまず一件落着といったところであるか。

ただし、デスクトップ環境で、これまで長年使ってきた Apple Wireless Keyboard が併用できなくなると考えた方がよさそうなので(Apple Wireless Keyboard Driver を使っても、スリープ後キー入力出来ない不具合を解消できるかどうか、トラブルシュートしてる精神的余裕がない...)、デスクトップ環境でのキーボード環境をどうしたものか、今後の課題である。
 


# by developer-adjust | 2018-08-28 18:37 | その他IT系 | Comments(0)
2018年 07月 23日

空のフォルダをコンテンツに含む NuGet パッケージのソースコードを Git でバージョン管理する

何を言っているのかわからないかもしれないが、とにかく記す。

こんな感じの、空のフォルダをコンテンツに含む NuGet パッケージを作ったとする。
d0079457_22214342.png
この NuGet パッケージを作るための .nuspec ファイルはこんな感じで、
<?xml version="1.0" encoding="utf-8"?>
<!-- 例えばファイル名は Foo.nuspec とか。-->
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>Foo</id>
<version>0.1.0</version>
<authors>(authors)</authors>
<description>(description)</description>
</metadata>
<files>
<file src="Content\" target="Content" />
</files>
</package>
上記、file 要素で指定している Content フォルダの中に、収録の目的である空のフォルダ "Controllers" を設けてある (下図)。
d0079457_22213924.png

これで、(nuget.exe が PATH 上にある前提で) "nuget.exe pack Foo.nuspec" を実行することで、空のフォルダをコンテンツに含む NuGet パッケージ "Foo.0.1.0.nupkg" ができあがる。

めでたしめでたし、なのだが...

Git では空のフォルダはバージョン管理下に登録されない

このような NuGet パッケージ作成プロジェクトを Git のバージョン管理下においたとする。

ところがである。

Git はその仕様上、空のフォルダはバージョン管理のリポジトリに登録できないのだ。

なので、このプロジェクトの Git リポジトリを clone すると、空のフォルダ (この例では "Content"、及びそのサブフォルダの "Controllers") が復元されない。

その結果、clone した先の作業フォルダで NuGet パッケージ生成を実行しても、下記のようなエラーになってしまう。
Attempting to build package from 'Foo.nuspec'.
Could not find a part of the path '...\Content'.

Git で空のフォルダをバージョン管理に含める方法

自分が知る限り、Git で空のフォルダをバージョン管理に含める直接的な方法は存在しない 。

その代わり、".gitignore" や ".gitkeep" など、何かしらのファイルを配置し、そのファイルを Git バージョン管理に含める事をもって、clone 先でも確実に当該フォルダが作成されるようにする、という回避策が一般的かと思う。

ということで、この NuGet パッケージ作成プロジェクトでも、"Content\Controllers" フォルダに ".gitkeep" を配置し、これを Git バージョン管理に追加してみる (下図)。
d0079457_22213366.png

そうすると、当然のことながら、このリポジトリの clone 先でも "Content\Controllers" フォルダが再現され、nuget pack コマンドが成功するようになった。

しかし、である。

今度は、できあがった NuGet パッケージに、".gitkeep" ファイルが含まれてしまった (下図)。
d0079457_22212814.png

これでは、この NuGet パッケージをインストールすると、本当は空っぽのフォルダができあがるのが期待値であるところ、".gitkeep"
ファイルが「ゴミ」ファイルとして配置されてしまう。

exclude 指定してみるが...

それではということで、.nuspec ファイルの指定にて、".gitkeep" を対象ファイルから除外してみた。
...
<files>
<file src="Content\" target="Content" exclude="**\.gitkeep" />
</files>
</package>
これでイケるだろうと思いきや、なんと、下記エラーとなってしまった。
Attempting to build package from 'Foo.nuspec'.
Error NU5017: Cannot create a package that has no dependencies nor content.
ぐぬぬ。

exclude 指定でもなく、".gitkeep" ファイルでもなくて...

あーでもないこーでもないと、検索しまくっているうちに、下記の NuGet の Issue にたどり着いた。


なんと、"_._" というファイルは、NuGet パッケージ作成の際に無視されるらしい。

マジか。

半信半疑で下図のとおり配置し、nuget pack コマンドを実行したところ...
d0079457_22211806.png

ちゃんと、"_._" ファイル抜きで、空のフォルダを含むコンテンツが、.nupkg 内に再現できた!
d0079457_22214342.png
"_._" ファイルは、Git にとっては何の変哲もない "ただのファイル" に過ぎないので、普通に Git バージョン管理に登録できる。

これで万事解決と相成った。


# by developer-adjust | 2018-07-23 22:33 | .NET | Comments(0)
2018年 06月 29日

ASP.NET Core 2.1 の UseHttpsRedirection が Azure Web Apps 上では効かない?

HTTPS プロトコルでのアクセスを強制する

ASP.NET Core 2.1 から登場した、Microsoft.AspNetCore.HttpsPolicy NuGet パッケージにて提供されている HttpsRedirection ミドルウェアを使うと、ASP.NET Core 2.1 Web サイト/アプリに、HTTP プロトコルでのアクセスがあったら HTTPS プロトコルのアクセスにリダイレクトさせる機能を実装できる。

例えば Visual Studio IDE 2017 で開発している場合は、Visual Studio IDE のプロジェクト新規作成のダイアログにて、この HTTPS リダイレクト機能込みでプロジェクトを作成する選択肢が用意されている。
d0079457_18505533.png
こうして作成した ASP.NET Core 2.1 Web アプリの Startup.cs を覗いてみると、Configure メソッド内にて、「app.UseHttpsRedirection()」というように、HttpsRedirection ミドルウェアの組み込みを行っている行があるのがわかる。
d0079457_18505199.png
この状況で、ローカル開発環境で実行してみると、たしかに http://localhost:... のアクセスは https://localhost:... へのアクセスにリダイレクトされている。
d0079457_18504680.png

Azure Web Apps 上では、デプロイするだけでは NG

それではこの ASP.NET Core 2.1 Web アプリを Azure Web App に発行してみたらどうなるか。

残念ながら (?)、それだけでは HTTPS プロトコルへのリダイレクトは機能しない。
d0079457_18504183.png
ドキュメントを確認してみると、HttpsRedirect ミドルウェアによる HTTPS プロトコルへのリダイレクトは、ある一定の条件が必要らしい。

ここでは、「環境変数 ASPNETCORE_HTTPS_PORT に、HTTPS プロトコルで接続するときのポート番号が指定されている場合」を、Azure Web Apps に適用して、HTTPS プロトコルへのリダイレクトが発動するように試してみた。

具体的には、Azure ポータル上から、当該 Web App のアプリケーション構成の設定ブレードを開き、下図のように HTTPS_PORT = 443 (※ポート番号 443 は HTTPS プロトコルの標準のポート番号) に設定する。
d0079457_18503398.png
こうすると、Azure Web Apps 上に発行後でも、HTTPS プロトコルへのリダイレクトが機能するようになった。
d0079457_18530444.gif
以上!
 

# by developer-adjust | 2018-06-29 19:02 | .NET | Comments(0)
2018年 05月 23日

気が付いたら Visual Studio Code / Visual Studio 2017 IDE で TypeScript の import 文が自動挿入されてた件

import 文をコーディングするのがストレス!

TypeScript による Web フロントエンド実装をコーディングしていての話。

個人的に、長らくの間、import 文を記述するのが億劫でならなかった。

いくらインテリセンス/コード補完があるとはいえ、下記 GIF アニメでわかるように、カレットを右に・左に・また右に、みたく忙しく動かさねばならないからだ。
d0079457_22234990.gif
左から右へ流れるようにタイプするだけの構文だったら、まだ救われたのかもしれないが...。

あと、例えば上記例のように、Angular4+ の HttpClinet サービスを必要とするコンポーネントやサービスをコーディングするときは毎回、この import 文を書かねば HttpClinet 型の参照すらままならず、正直、かなりイライラさせられていた。

あれ、何ですか、この神機能!

ところがである。

ふと、ある日、Visual Studio 2017 IDE を使用して、またしても HttpClient を DI 機構で受け取るコンポーネントのコンストラ引数を (import 文書くより前に、ついうっかり) コーディングしていると、なんと、まだ import していない HttpClient クラスがインテリセンスの候補に挙がってきているではないですか (下図)。
d0079457_22241922.png
そして、何かの見間違いかと思いつつ、そのまま Tab キー押して候補を確定したところ、なんと、import 文が自動挿入されたのである。
d0079457_22240032.gif
あわてて (常用していない) Visual Studio Code を起動して同じプロジェクトを開いて動作を試してみたところ、Visual Studio Code でも、この、import 前の型の候補表示 & 自動 import 挿入が発動した。
d0079457_22240959.gif
これはきわめて便利!

これまでの import 文コーディングに関する不満が吹き飛んだ。

いつから使えてたのか/どうやって実現してるかは不明のまま放置

この機能はいつのバージョンから使えるようになっていたのだろう?
とりあえず Visual Studio 2017 IDE については、v.15.7 に更新したあたりで気づいたのだが、もっと前からサポートされていたのだろうか?

リリースノートを確認すればはっきりしたことがわかるとは思うが、とにかく、2018年5月時点で最新版の Visual Studio Code 及び Visual Studio 2017 IDE を使っていれば、この機能の恩恵にあずかれるっぽい。

また、この import 前の型の候補表示 & 自動 import 挿入が、どのような仕掛けで機能しているかは、まだよくわかっていない。

packages.json を見てるのか、webpack.config.js を見ているのか、node_modules フォルダ以下をスキャンしているのか、はてさて。

しかし何はともあれ、数字としてタイピング量を減らすという以上に、コーディング時の心理的疲弊をばっちり回避できる、素晴らしい機能だと思った。

※ Atom や Sublime、Vim などなど、そのほかのリッチ系エディタについても、同様のサポートがあるのかどうかは知らない。ご存知の方は、ブログのコメントないしは Twitter 上などでお知らせいただけるとありがたい。

2018/05/25 追記
JetBrains 製の IDE、IntelliJ/WebStorm であれば対応してるよ、とのお知らせを頂戴した。

さすがは JetBrains である。

ところで、この Tweet ― 不要な import を削除する機能 ― を頂戴して、もしかしたら思い、Visual Studio 2017 IDE 上で Ctrl+R, Ctrl+G のキーボードショートカット (これは、C# ソースの編集中における、未使用の名前空間 using 節の削除を行なうショートカット) を打鍵してみたところ、TypeScript の未使用 import 削除としても機能した。

さらには、Visual Studio Code にも、April 2018 (version 1.23) から同様の機能が備わっているとのこと。
Visual Studio Code では、既定のキーバインドだと、Shift+Alt+O で発動するらしい。
TypeScript のソースコード保存時に自動で不要 import 削除を発動させることも、Visual Studio Code の設定で構成可能とのこと。

Visual Studio 2017 IDE でも、たしか、アドインを追加することで、保存時の不要 import 削除を自動化できるかもしれない (自分は未確認)。

# by developer-adjust | 2018-05-23 22:34 | Visual Studio | Comments(0)
2018年 04月 29日

Azure AD のユーザーアカウントのパスワード期限を無期限にする

Azure Active Directory (AzureAD)

Azure Active Directory (以下 AzureAD) は、Microsoft のパブリッククラウドサービス「Microsodt Azure」が提供する各種サービス機能のひとつ。

自分は、AzureAD を、自作のWebアプリの認証基盤として使用している。

すなわち、自作Webアプリのユーザー情報管理(ユーザーの追加・変更・削除)は、Azure のポータル Web サイトにおける AzureAD の画面で行い、且つ、ユーザーのサインイン処理(認証)も AzureAD が提供する機能・画面に任せて、自作アプリのほうはその認証の結果だけを頂戴するような形だ。

このように AzureAD を利用させてもらうことで、自作アプリ側に個別のユーザー情報管理機構を実装しなくて済む。

いわゆる "ID as a Service" って感じである。

AzureAD のユーザーアカウントのパスワードを無期限に

さてそのような AzureAD であるが、AzureAD 上で作成するユーザーアカウントは、パスワード有効期間は 90日という設定が課せられている。

通常はそれで問題ないことと思うが、諸事情により、どうしてもパスワード有効期間を無期限としたい要件が発生した。

検索サイトで調べてみたところ、まず、AzureAD ユーザーアカウントのパスワード有効期間を無期限とすることは可能ではあるとのこと。
が、但しその設定変更は、Azore ポータル Web サイト上からはできない、ということらしい。

その代わりに、Office365 管理用の PowerShell モジュールを介して PowerShell 上からコマンドレット呼び出しして行えばよい、との記事が多数ヒットした。

しかしながら実際にそれら記事に沿って試してみたところ、自分の場合、同じサインイン名で複数の AzureAD インスタンス (テナント、ディレクトリ) に出入りしているケースがあり、しかし Office365 PowerShell モジュールの接続コマンドレット「Connect-MsolService」ではテナントIDを明示して接続する方法がわからず、目的のディレクトリ上での作業ができなかった。

あれこれ試行錯誤するも、時間ばかり過ぎて業を煮やした自分は、"Msol" が名前に付く Office365 管理由来のコマンドレットではなくて、生粋の AzureAD を相手にする PowerShellモジュール/コマンドレットがないものか、再度検索サイトで調べなおした。

そうしたところ、AzureAD v2 と呼ばれる PowerShell モジュールを用いた下記手順があることを知り、設定作業に成功した。

AzureAD v2 を使ってパスワードを無期限に設定する

前提条件・事前インストール作業

まず前提条件としては下記のとおり。
  • PowerShell v.5.0 以降、64bit 版
  • .NET Framework v.4.5 以降
  • 上記が動作するOS (Win7 SP1以降、64bit)

この環境で、管理者として実行した PowerShell コンソール内で下記を実行し、AzureAD PowerShell モジュールをダウンロード & インストールする。
PS> Install-Module AzureAD
これで AzureAD PowerShell モジュールのインストールが完了し、以後この環境から AzureAD を操作する各種コマンドが使えるようになった。

AzureAD への接続

さて、ユーザーアカウントのパスワードを無期限とするためには、まずは PowerShell のセッションを、目的の AzureAD テナントに接続しておく必要がある。
接続のコマンドは下記のとおり。
PS> Connect-AzureAD -TenantId {ディレクトリID}
引数のテナントID(ディレクトリID)は省略もできるが、接続する AzureAD ディレクトリを明示的に指定したい場合に使える。

なお、ディレクトリ ID は、Azure ポータル Web サイトの AzureAD 管理画面中、「プロパティ」カテゴリの表示から知ることができる。
d0079457_22284992.png
さてこうしてコマンドレットを実行すると、認証用の GUI が表示される(下図)。
d0079457_22285532.png
ここで対象の AzureAD に対する管理者アカウントで認証を済ませ、接続するとよいだろう。
( Get-Credential コマンドレットを使って認証情報を変数に入れてから、Connect-AzureAD の -Credential 引数に渡す手順を解説している記事を多々目にした。が、個人的には上記手順のほうが手数が少なくて面倒がない気がしている。)

ユーザーアカウントの設定変更

ひとたび、Connect-AzureAD で PowerShell セッションを AzureAD に接続できたら、そのほかの AzureAD 関連コマンドレットが使えるようになる。

今回目的のパスワード有効期間を無期限とするユーザーアカウントの設定変更は、「Set-AzureADUser」コマンドレットを使って、以下のように実行する。
PS> Set-AzureADUser -ObjectId {対象ユーザーの ObjectID} -PasswordPolicies DisablePasswordExpiration

設定変更対象のユーザーアカウントは、そのユーザーアカウントの "ObjectID" で指定する。

ユーザーアカウントの ObjectID は、Azure ポータル Web サイトの AzureAD 管理画面から表示可能なほか、PowerShell セッション上で「Get-AzureADUser」を実行してディレクトリ中のユーザーアカウント一覧を表示させることでも知ることができる。

出典

以上、AzureAD PowerShell モジュールを使って、AzureAD 上のユーザーアカウントのパスワード有効期間を無期限に設定変更する手順である。

なお、-PasswordPolicies 引数及び DisablePasswordExpiration 指定についての出典は下記のとおり。

New-AzureADUser | Microsoft Docs

Set-AzureADUser | Microsoft Docs



# by developer-adjust | 2018-04-29 22:33 | その他IT系 | Comments(0)
2018年 03月 26日

最近お気に入りの Visual Studio 2017/Code の機能 - 「プロパティを作成して初期化する」

Visual Studio 2017、または Visual Studio Code を使って、C# のコーディングをしていての話。

頻出パターン - コンストラクタ引数で受け取りプロパティに格納

昨今の ASP.NET Core Web アプリ開発では、フレームワーク備え付けの DI (Dependency Injection:依存性注入) 機構によって、必要なサービスオブジェクトを参照するのが普通だ。

例えば Entity Framework Core のデータベースコンテキストオブジェクトをコントローラクラスで使いたい場合、コントローラクラスのコンストラクタにて、その引数にデータベースコンテキストオブジェクトを受け取るように実装する。

そして普通は、そうしてコンストラクタ引数で受け取ったオブジェクトを自身のプロパティで参照を押さえておき、のちのアクションメソッド内などから使用するのが常である。

この「コンストラクタ引数で受け取って、プロパティに格納」というコーディングは、今や頻出パターンである。

それだからであろうか、最新の Visual Studio IDE および Visual Studio Code には、このコーディングを支援するクイックアクション機能がいくつか備わっている。

その支援機能の中でも自分が好んで使うのは「プロパティを作成して初期化」クイックアクションだ。

「プロパティを作成して初期化」クイックアクション

「プロパティを作成して初期化」クイックアクション機能の利用手順はこうだ。

Visual Studio 2017 ないしは Visual Studio Code でクラスのコーディング中において、コンストラクタの引数をまず実装する。

話がそれるが、引数の型名を入力してスペースまで打鍵した段階で、引数名の提案 (Suggest) が出てくるのも便利。
多くの場合、そのまま Tab キー打鍵で引数名のコーディングが済んでしまう。
d0079457_22101539.png
話を戻そう。

そうやってコンストラクタ引数のコーディングが済んだら、すかさず Ctrl + . (ドット) を打鍵する。

するとこれがクイックアクション発動のキーバインドになっているため、既定のクイックアクション「プロパティを作成して初期化」が初期選択された状態でクイックアクションのメニューが開く。
d0079457_22101428.png
そのまま Enter を打鍵すれば、以上で getter のみのプロパティとそのプロパティの初期化コードが生成される。
d0079457_22101468.png

このように、
コンストラクタ引数をコーディング ⇒ CTrl + . ⇒ Enter
という、
たったこれだけのキー操作で、「コンストラクタ引数で受け取ったオブジェクトをプロパティに格納」がコーディングできてしまう
のが「プロパティを作成して初期化」クイックアクションだ。
d0079457_22113013.gif

ほかにもいろいろな手順でコーディング支援してくれる

この機能、あるきっかけで気が付いた。
恥ずかしながら、Visual Studio 新バージョンが出てもろくにリリースノート読んだりしてなかったので、いつのバージョンからこの機能が使えたのかはよくわかってない (もしかして、かなり昔から使えてた...?)。

が、とにかく、Visual Studio IDE および Code の両方で、「プロパティの作成と初期化」クイックアクションによるコーディング支援が受けられる。


詳しくは下記公式ドキュメントに説明がある。

このドキュメントを見ると、プロパティではなくフィールドを使用することもできることがわかる。

また、ほかにも「コンストラクタ引数で受け取って、プロパティに格納」をコーディングする支援機能はいろいろあるようだ。

例えば、先にプロパティをずらずらをコーディングしておき、それらプロパティを選択してからクイックアクション発動で、コンストラクタのほうを自動生成する、といった手順も可能だ。


ということで、「コンストラクタ引数で受け取って、プロパティに格納」が頻出パターンなプロジェクトにかかわっているのに、私のように、この、Visual Studio 2017/Code が提供してくれている「プロパティの作成と初期化」クイックアクションをまだ知ってなかった! という稀有な方は、これを機会にぜひ試用してみていただき、ご自身のコーディング人生をより幸せなものにしていただければと願う。
 


# by developer-adjust | 2018-03-26 22:41 | Visual Studio | Comments(0)