検索
リンク
タグ
ライトニングトーク
.NET
WebMatrix
Selenium
AngularJS
Fizz-Buzz
F#
Azure
jQuery
Plone
AJAX
Visual Studio
C#
ASP.NET MVC
ASP.NET
JavaScript
SQL Server
ADO.NET Entity Framework
LINQ
ASP.NET Core
カテゴリ
最新の記事
最新のコメント
記事ランキング
最新のトラックバック
以前の記事
2019年 11月 2019年 10月 2019年 09月 2019年 08月 2019年 07月 2019年 06月 2019年 05月 2019年 04月 2019年 03月 2019年 02月 2019年 01月 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月 ファン
ブログジャンル
画像一覧
|
1 2019年 08月 29日
背景 - EFCore が出力する SQL 文を知りたいデータベースを読み書きする ASP.NET Core Web アプリ実装において、データベースアクセスライブラリの選択肢としてとりあえずオーソドックスな "Entity Framework Core" (以下 EFCore)。 EFCore およびその前身である "Entity Framework" の面白いところは、データベースクエリの結果をオブジェクトに "マップ" する O/R マッパーというだけでなく、C# コードとして記述されたラムダ式木に基づく SQL クエリビルダーでもあるという側面がある。 さてそんな EFCore であるが、だがしかし、期待していたのとは異なる SQL が発行される可能性も少なくない。 とくに EFCore の ver.2.x だと、GROUP JOIN ですら、簡素な SQL を発行して早々にデータベースから多量のレコードをオブジェクトとして読み込んでしまい、オンメモリで残りの処理を実行することもあるという。 なお、本ブログ執筆時点では未だリリースされていない、次バージョン EFCore 3.x では、このあたりの挙動が変更され、SQL に変換できないクエリは例外を発生させることになるらしい。 この辺りの話題は、下記などが参考になる。 そんなこともあり、とくにアプリ開発中は、EFCore が発行する SQL 文を確認したいところである。 なお、コンソールアプリなどで EFCore 使用時に、その発行する SQL を確認するには、その目的のロギング機構を組み立てて適用すればよい。 詳しくは下記などが参考になる。 実は開発時ログ出力には、既に含まれているさてさて、ASP.NET Core アプリ開発中は、一般的なプロジェクトテンプレートから起こしたプロジェクトであれば特に、すでにロギング機構が組み込まれており、且つ、開発時向けのログレベル構成が適用済みである。 下記は開発時用構成ファイルである appSettigs.Development.json 中のログレベル構成だ。
この構成だと、Visual Studio で開発中であれば、Visual Studio の出力ウィンドウに色々ログが流れているのが確認できる。 (※デバッガなし実行でも表示される) また、dotnet CLI を使ってる場合も "dotnet run" などで実行すると、コンソールにログが流れるのを見ることができる。 実は既に、EFCore が出力する SQL 文は、このログの中に表示されているのだ。 よーく見ると、EFCore が出力する SQL 文が、ログの中に表示されているのを見つけることができる (下図、赤丸のところ)。 ![]() 大量のログ出力に埋もれてしまう...しかしである。 上図でもわかるように、このままでは、ブラウザ等からの要求ごとの ASP.NET Core 関連ログが大量に発生し、EFCore の SQL 文ログがそれらログに埋もれてしまう。 (ないしは、あっという間にスクロールアウトしてしまう) 実際問題として、この構成のままでは、大量のログの中から EFCore が出力する SQL 文を探し出して確認するという作業はあまり現実的ではない。 これは個人的な意見であるが、実のところ、ASP.NET Core 関連の要求処理時の情報ログは、あまり必要を感じない。 どのようなリクエストがブラウザから発生しているかを見るときは、どちらかといえば、ブラウザの開発者ツールで確認するだけで用が足りることがほとんどだ。 EFCore 以外のログレベルを調整ということで、appSettings.Development.json を改訂し、"Microsoft" カテゴリのログレベルを "Information (情報)" から "Warning (警告)" レベルに引き上げてしまうと良かろう。 そうすることで、ASP.NET Core 関連の大量の情報ログが表示されなくなる。 ただしそれだけだと、EFCore の SQL 文出力も同じく表示されなくなってしまう。 そこで、EFCore の SQL 出力だけはログ出力されるよう、"Microsoft.EntityFrameworkCore.Database.Command" カテゴリのログレベルを、再び "Information" としてオーバーライドするとよい。 最終的な appSettigs.Development.json は下記のような感じになる。
これで下図のような感じで、EFCore の出力する SQL 文だけが都度流れるようになる。 ![]() 自分の開発スタイルとしてはこれくらいのログレベルでちょうどいい感じだ。 以上、すべてのケースでこのログレベル構成が最適とは言わないが、同じような境遇の人にこの情報が役に立てば幸いである。 補足データベースアクセスのためには、EFCore 以外にも選択肢はいろいろあるので、発行される SQL を完全に制御したい場合などは、無理に EFCore を使う必要もない。 下記など参考にされたし。 ▲
by developer-adjust
| 2019-08-29 21:11
| .NET
|
Comments(0)
2019年 07月 06日
C# による ASP.NET Core プログラミングにおける、単体テストを実装していての話題。 ネットで検索すればすぐに見つけられるような内容かとも思うが、自分の為の備忘録を兼ねてここに記す。 さて、前述のとおりの単体テストを実装している際、IOption<T> をコンストラクタ引数に求めるオブジェクトをテスト対象とすることがある。 さらにたまーにではあるが、コンストラクタ引数に IServiceProvider を直に要求するオブジェクトを扱うこともある。 このようなケースで、どのように IOption<T> ならびに IServiceProvider をテストプログラム中でインスタンス化すればよいか、という話である。 IOption<T>ASP.NET Core におけるオプション構成は、通常は Startup クラス中の ConfigureServices メソッド内で初期化するのが通常だ (下記は MyOptions 型のオプションを appSettings.json などの構成情報から読み取って取得する例)。
こうしておくと、MVC/API コントローラなどで MyOptions 型のオプション情報が必要な場合は、そのコンストラクタ引数として IOptions<MyOptions> 型の引数を用意しておけば、依存性注入機構によって引き渡されるようになっている (下記例)。
さてこのような IOption<T> を自前のテストコード中で直に生成するには、Microsoft.Extensions.Options 名前空間の Options クラスの Create<T>(T options) 静的メソッドを用いる。 この Create<T>(T options) 静的メソッドの引数に、任意の型 T のオブジェクトを渡せば、その戻り値で IOption<T> が返る (下記例)。
IServiceProviderIServiceProvider を自前のテストコード中で生成するには、Microsoft.Extensions.DependencyInjection 名前空間の、ServiceCollection クラスを使う。 手順としては、まずは ServiceCollection クラスをインスタンス化する。 次にこの ServiceCollection オブジェクトに対し、AddSingleton<T1,T2>() などをはじめとしたおなじみのメソッドを呼び出して、そのテストで必要となるサービスを登録しておく。 (すなわち、IServiceProvider を要求しているテスト対象のコード中では、その IServiceProvider に対して GetService<T1>() とか呼び出して、サービスを入手しているであろうため) 以上の準備が整ったら、ServiceCollection オブジェクトの BuildServiceProvider() メソッドを呼び出す。 そうすると、BuildServiceProvider() メソッドの戻り値として、IServiceProvider が返る。
使い終わったら、Dispose() メソッドを呼び出してリソース破棄しておくことを忘れずに。 以上!
▲
by developer-adjust
| 2019-07-06 23:02
| .NET
|
Comments(0)
2019年 02月 26日
.NET Core SDK 環境のみで Sass (SCSS) をコンパイルするC# による Web アプリ・サーバー側実装のフレームワーク ASP.NET Core を使った、Web アプリプログラム開発での話。最近はフロント側を Angular で書くようになったため、Sass (SCSS) を CSS にコンパイルするのは、webpack によるモジュールバンドリング処理の一環として webpack の loader で行なう必要があり、実際そのようにしている。 しかし他方、Angular などのフロント側フレームワークに依らない、静的なちょっとした Web サイト作成や、C# でフロント側を実装する Blazor のようなフレームワークを使うケースでは、Sass (SCSS) ファイルを css ファイルにコンパイルする方法は、必ずしも webpack に頼る必要はない。 実のところ、.NET Core プロジェクトのビルドシステムにおいては、nuget.org で公開されているライブラリ (NuGet パッケージ) による支援もあって、Sass (SCSS) を css にコンパイルすることが可能だ。 .NET Core SDK さえ開発マシンにインストールされていれば、Node.js などがインストールされていなくても、Sass (SCSS) コンパイルが可能なのである。 ただ、現時点では .NET Core プログラムのビルドの一環として Sass (SCSS) コンパイルを実施することが可能、という状況なので、プロジェクトファイル (.csproj など) が必須である。 実際にやってみる.NET Core プログラムのビルドの一環として Sass (SCSS) コンパイルを実施するには、まず、以下の NuGet パッケージを当該プロジェクトにパッケージ参照追加する。 dotnet CLI であれば、対象プロジェクトがあるフォルダをカレントディレクトリにして、下記を実行すればよい。 > dotnet add package BuildWebCompiler Windows OS 上で Visual Studio を使っている場合は、GUI のパッケージマネージャから追加してもよいだろう。 ![]() 次に、対象プロジェクトのルートフォルダに以下のような内容の設定ファイル "compilerconfig.json" を作成する。
以上で設定完了だ。 上記 compilerconfig.json の inputFile で指定した Sass (上記例だと SCSS 形式だが) ファイル "wwwroot/css/test.scss" を作成し、ビルドを実行する。 そうすると、この Sass (SCSS) ファイルがコンパイルされて、outputFile で指定されたファイル名の CSS ファイルが出力されるのが確認できるはずだ。 さらにオマケとして、出力先 css ファイルは、そのミニファイ版も同時に生成される(ファイル名は .../test.min.css となっている)。 compilerconfig.json にどのような記述ができるかは、あまり詳しいリファレンスは見つけていないものの、先の NuGet パッケージの GitHub リポジトリにある README (下記 URL) が参考になる。 このように、.NET Core SDK 環境だけでも、プロジェクトのビルドの一環として、Sass (SCSS) ファイルを css にコンパイルすることが可能である。 ちなみにこの BuildWebCompiler NuGet パッケージ、実は Sass (SCSS) -> css コンパイルのみならず、LESS や CoffeeScript などなど、様々な変換が可能だ。 自分では実際には試したことがないが (※CoffeeScript 書くスキルがない...)、もし需要があるなら試してみるとよいかもしれない。 Sass (SCSS) -> CSS コンパイルだけ実行するビルド時に Sass (SCSS) -> CSS コンパイルができるようになったが、しかしながら開発中は、.scss を編集するだけでいちいちプロジェクト全体をビルドはしたくないところである。 dotnet CLI を使うなら、対象プロジェクトがあるフォルダ上で下記 dotnet コマンドを実行することで、Sass (SCSS) -> CSS コンパイルだけを実施することが可能だ。 > dotnet msbuild -t:WebCompile -nologo ウォッチさらにできれば、.scss ファイルを保存したら自動で .css にコンパイルしてくれたら嬉しい。 そのためのやり方のひとつとして、「ファイルの変更を監視し、変更されたらタスク (この場合は .scss > .css のコンパイル) を実行する」という "ウォッチ" 方式がある。 このウォッチ方式による .scss > .css 自動コンパイルの実現は、dotnet CLI のウォッチ機能を利用することで可能となる。 ただし残念ながら自分が知る限り、ちょっとだけ事前の手順が必要。 まず対象プロジェクトファイルをテキストエディタで編集し、下記の要領で .scss ファイルを監視対象に含めるようプロジェクトを構成する必要がある。
上記変更を施したら、対象プロジェクトがあるフォルダ上で下記 dotnet コマンドを実行することで、ファイル変更の監視を行なう dotnet CLI が常駐する。 > dotnet watch msbuild -t:WebCompile -nologo この状態で .scss ファイルを上書き保存すると、.scss > .css コンパイルが実行されるようになる。 なお、dotnet CLI の watch 機能は、監視対象のファイルを状況に応じて使い分けることが難しいようで、例えばこの状態で、同プロジェクトに含まれる C# ソースコード (.cs ファイル) を上書き保存しても、.scss > .css コンパイルが走ってしまう。 dotnet CLI の watch 機能を、このプロジェクトでは .scss > .css コンパイルにしか使わない、という場合は、プロジェクトファイルに以下のとおり追記して、C# ソースコードファイルを監視対象から除外することが可能だ。
IDE/エディタの拡張機能もあるが...以上ここまで、.NET Core SDK 環境で、プロジェクトのビルドの一環として Sass (SCSS) を CSS にコンパイルする方法について説明してきた。 なお、Sass (SCSS) を CSS にコンパイルする方法としては他にも、Visual Studio のような IDE や、Visual Studio Code などのエディタにおける「拡張機能」を利用することもできる。 実際、Windows OS 上で Visual Studio を使う場合は下記拡張を Visual Studio にインストールしておくと、Visual Studio 上での .scss ファイルの編集・保存時に .css へのコンパイルが実行されるようになる。 実のところ、これまで説明してきた、.NET Core アプリプロジェクトのビルド時に Sass (SCSS) コンパイルが実行されるやり方で使用した に BuildWebCompiler NuGet パッケージと上記 Visual Studio 拡張は同じコードベースで作られている。 そのため、先に説明した compilerconfig.json の設定を読んで同じように動作するので大変使い勝手が良い。 あと、同じ理由で、この Visual Studio 拡張も Sass (SCSS) のみならず LESS やら CoffeeScript やらもファイル保存時のコンパイルが可能だ。 また、Visual Studio Code であれば、下記の拡張が人気があるようだ。 このように、IDE やエディタの拡張機能を用いることで、.scss ファイル保存時に自動で .css にコンパイルすることができるようになり、このほうが開発者体験としてはより良いように感じる。 とはいえ、開発メンバー全員の IDE/エディタ環境を揃えるのが手間だったりうまくいかないことがあるかもしれない。 開発環境を再構築後に、うっかり拡張を入れ忘れてしまい、.scss を変更・保存したけれども、対応する .css が更新されずしまい、というバグだって引き起こしてしまうかも知れない。 そうしたケースに備える目的で、ソースコードをリポジトリから git clone するだけで、開発環境への各種拡張の追加インストールすることなく、最低限ビルドすればちゃんと .scss が .css にコンパイルされるようになるのは、これはこれで便利で大事なことだと思う。 補足これまでの説明では、あくまでも .NET Core アプリ開発としての説明としてきたが、実は BuildWebCompiler NuGet パッケージは、.NET Framework のプロジェクトに追加しても同じように動作する。 これまでの説明における dotnet CLI を使った用法はできないが、Visual Studio 上で .NET Framework 用アプリ開発時でも、同じようにビルド時に Sass (SCSS) ファイルを CSS ファイルにコンパイルすることが可能となる。 ▲
by developer-adjust
| 2019-02-26 22:01
| .NET
|
Comments(0)
2018年 12月 28日
背景Visual Studio や dotnet CLI + お好みのエディタなどを使っての、ASP.NET Core Web アプリを開発中の話。 開発中の ASP.NET Core Web アプリを、エミュレータではない実機のモバイル端末 (iOS や Android など) から接続して動作確認したいことはよくある。 その実現方法としては、例えば ngrok を使ってローカル開発中の ASP.NET Core Web アプリをインターネット上に晒し、そこにモバイル端末実機のブラウザから接続しにいくのもアリではある。 とはいえ、開発途上のものを、一時的とはいえインターネット上に晒すのは危険が伴う。 そもそも通信経路が長くなる上、ngrok の処理性能やモバイル回線の速度・帯域にも大きく左右されて、すばやい動作確認、トライ&エラーの繰り返しがやりにくい。 ということで、顧客に見てもらうなどの理由がない限りは、開発機と同一ローカルエリアネットワークに Wi-Fi 接続したモバイル端末実機から、同ネットワーク経由で接続するのが普通かと思う。 ただ、ASP.NET Core Web アプリの既定のプロジェクト構成では、開発中の ASP.NET Core Web アプリはローカルホスト (127.0.0.0/24, ::1) でしか待ち受けしていない。 なので、当該開発機の外部からは、そのままでは接続できない。 そこで、プロジェクト構成を変更する必要がある。 Visual Studio 上からの設定変更Visual Studio で開発中の場合、お勧めの方法は以下のとおり。
![]() 以上で Ctrl+F5 で実行などすれば、当該開発機の外部からも、この ASP.NET Core Web アプリが接続を受理、応答を返すようになる。 なお、上記で行なった設定内容は、Properties フォルダ内にある、「launchSettings.json」というファイル名の JSON ファイルにその設定内容が保存されている。 例えば次のとおり。
"dotnet run" で実行する場合dotnet CLI を用いた "dotnet run" による実行でも、上記 launchSettings.json に基づいて ASP.NET Core Web アプリを立ち上げる。 なので、 dotnet CLI を使っての開発中の場合でも、上記のように launchSettings.json を作成・記述しておけばそれだけでよい。 また、先の説明では端折ってしまったが、設定のキモは、環境変数 ASPNETCORE_URLS の設定である。 標準のプロジェクトテンプレートで作成された ASP.NET Core Web アプリであれば、環境変数 ASPNETCORE_URLS を見て、そこに設定されている待ち受け URL を採用するようにできているのだ。 先で説明している launchSettings.json の内容も、要するに環境変数 ASPNETCORE_URLS を設定しているわけである。 なので、launchSettings.json がなくても、コマンドプロンプト (ターミナル) で下記のように環境変数 ASPNETCORE_URLS を設定してから dotnet run を実行することでも OK だ。
※ "dotnet run" を実行したコマンドプロンプト (ターミナル) 内で環境変数 ASPNETCORE_URLS を設定しつつ、 launchSettings.json でも環境変数 ASPNETCORE_URLS を設定していた場合は、 launchSettings.json の設定のほうが優先する。 補足: アプリケーション URL を設定すればよいのでは?ホストアドレスに「0.0.0.0」を指定実は、Visual Studio での設定時、環境変数 ASPNETCORE_URLS ではなく、[アプリケーション URL] に、「https://0.0.0.0:5001;http://0.0.0.0:5000」というように、ホストアドレスを「0.0.0.0」とした待ち受け URL を設定することでも、外部からの接続を受け付けるようになる。 ![]() 但し上図の設定だと、IPv4 アドレスでのみ待ち受けすることになるので注意。 すなわち、開発機上のブラウザでアドレスバーに「https://localhost:5001」や「http://127.0.0.1:5001」と入力するぶんには当該 Web アプリにアクセスできるものの、IPv6 アドレスである「https://[::1]:5001」を入力すると、接続不能となるのである。 まぁ、「開発中の Web アプリをモバイル端末実機で確認」という用途であれば、IPv4 アドレスのみでの待ち受けで十分事足りる気もする。 なので、実際上は、上図のようなアプリケーション URL 設定による方式で十分かもしれない。 もっとも、IPv6 アドレスでも待ち受けさせることももちろん可能で、その場合はホストアドレスとして「[::]」を指定すればよい。 例えば「https://0.0.0.0:5001;http://0.0.0.0:5000;https://[::]:5001;http://[::]:5000」というようにアプリケーション URL を設定すれば、IPv4 でも IPv6 でも、外部からつながるようになる。 ただ、ちょっと設定が長すぎではある。 アプリケーション URL 設定で、ホストアドレスに「*」を指定しないのはなぜ?アプリケーション URL 設定に、(環境変数 ASPNETCORE_URLS での設定と同じように)「https://+:5001」とか「https://*:5001」 のように、ホストアドレスとして「+」や「*」を指定すれば、 IPv4 と IPv6 の設定を併記しなくて済むのでは? とも思われた。 試しにやってみたところ、 launchSettings.json を直接編集して "applicationUrl" に "https://*:5001" を設定し、dotnet run で実行するぶんにはうまくいった。 しかし launchSettings.json がこの状態で、当該プロジェクトを Visual Studio で開き、Ctrl+F5 実行すると、「Invalid URI: The hostname could not be parsed.」というエラーメッセージボックスを表示して起動してくれない。 また、Visual Studio 上からは、アプリケーション URL に + や * をホストアドレスとした URL を設定すると入力検証エラーになって設定できない。 加えて、先のとおり launchSettings.json を直接編集した状態でプロジェクトのプロパティ画面から [デバッグ] セクションを開いてしまうと、場合によっては入力検証エラーに阻まれ、プロパティ画面を閉じたり保存したりができなくなり、どうにもならない "詰んだ" 状況に陥ってしまう。 ...これらのことから、環境変数 ASPNETCORE_URLS に待ち受け URL を設定する方式がいちばん一貫性もあり、自分のお勧めの方法と結論づけている。 補足: [ブラウザを起動] の URL を明記するのはなぜ?dotnet run で実行するぶんには、 launchSettings.json の "launchUrl" は無くても (あるいは空文字であっても) なんら問題ない。 本稿作成時点では、dotnet run では、ブラウザの起動までは行なわないからだ。 しかし Visual Studio 上で開発・実行してブラウザも開きたいというケースでは、[ブラウザを起動] の URL を明記しておかないと厄介なことになる。 まず、環境変数 ASPNETCORE_URLS に待ち受け URL を設定する方式の場合、Ctrl+F5 実行すると、Web アプリのプロセスは起動するものの、Visual Studio がエラーメッセージボックスを出してブラウザ起動に至らない。 また、アプリケーション URL にホストアドレス 0.0.0.0 で設定する方式の場合、Ctrl+F5 実行すると、ブラウザは起動するものの、「https://0.0.0.0:5001」という URL を開いてしまってアクセスできない結果となる。 なので、少なくとも Visual Studio 上での実行でブラウザも同時に開きたいケースでは、ちゃんと [ブラウザを起動] の URL を明記しておくに越したことはない。 補足: IIS Express での実行時について書かれてないけど?需要と余力があれば調べて試して本ブログに投稿する...かもしれない。
▲
by developer-adjust
| 2018-12-28 22:37
| .NET
|
Comments(0)
2018年 09月 28日
ASP.NET Core アプリのアプリケーション構成ASP.NET Core アプリは、標準のプロジェクトテンプレートで作成すると、プロジェクトのフォルダにある appSettings.json というファイルを読みこんで、アプリケーション構成として使用するようにできている。 この appSettings.json にアプリケーション固有の半固定パラメータなどの設定値を JSON 形式で記述しておき、アプリ中からその設定値を読み取って利用する、というものだ。 詳しくは下記を参照するとよいだろう。 例えば下記のような appSettings.json を用意したとして、
ASP.NET Core アプリの実装コード (今回は C#) で、下記のように、上記 appSettings.json の JSON 構造にマッピングされるクラスを用意して、
ASP.NET Core アプリの Startup クラスにて、下記のように、appSettings.json ファイル中の SiteSettings ノード以下を DI コンテナへサービス登録することで、
`IOptions<SiteSettings>` 型のインスタンスを DI 機構によって入手できるようになる。 この `IOptions<SiteSettings>` オブジェクトの各プロパティを参照すると、appSettings.json の記載内容が SiteSettings オブジェクトにマッピングされて読み取られ、参照可能となっている寸法だ。
アプリケーション構成の "上書き"この appSettings.json に記載されている設定値だが、いくつかの方法で "上書き" が可能だ。 ひとつは appSettings.Develop.json に記述する方法。 開発環境での実行時は、appSettings.json の設定値に対して、appSettings.Develop.json に記述した設定値で上書きされたように、アプリ側では設定値を読み取るようにできているのだ。 この仕組みにより、appSettings.json には既定値を、appSettings.Develop.json には各開発者固有の環境依存の設定値など(例えばデータベースの接続先設定値とか)を記載しておいたりして、アプリの動作を調整できる。 例えば先の例だと、appSettings.Develop.json に以下のように記述しておくと、
アプリ側の読み取り結果は下記のとおりとなる。
なお、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 アプリは起動時にクラッシュしてしまう。
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.」 というように、重複キー発生である例外メッセージがコンソール出力から読み取れる。 ![]() 環境変数で "上書き"アプリケーション構成を上書きするもうひとつの方法は、環境変数で "上書き" する方法である。 appSettings.json 中の各セクション (ノード、プロパティ) 名を、コロン (:) 区切りで連結した名前で環境変数を定義すると、その環境変数の値がアプリケーション構成として読み取れるのだ。 言い換えると、C# や JavaScript 上、ドット (.) で区切るところをコロン区切りに置き換えた名前、とも言える。 先の例でいくと、例えば環境変数 "SiteSettings:TimeZone:Offset" に "8" と設定してから実行すると、アプリでの読み取り結果は下記のとおりとなる。
Windows OS 上で Visual Studio を用いて開発・実行している場合は、Visual Studio の画面上、プロジェクトのプロパティ画面から環境変数を設定することもできる。 ![]() このやり方だと、環境変数の設定を変更して保存 (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" のところに指定してやれば良い。 ![]() "上書き" というよりは "合成" と言ったほうがイメージあってる?これら "上書き" の動作だが、優先順位としては次のとおり。 環境変数 > appSettings.Develop.json > appSettings.json 上記3者で同じセクション名で異なる値をそれぞれ設定していた場合、環境変数による設定が勝つ。 また、"上書き" とは言ったが、appSettings.json 内に記述のないセクション名のアプリケーション構成を、環境変数で設定してあれば、アプリ側ではちゃんと読み取れる。 例えば appSettings.json に SiteSettings.Title がなくても、
環境変数 "SiteSettings: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 クラスでも配列としている。
試したところ、実はここ、配列じゃなくても大丈夫だった。 "List<T>" でも "IEnumerable<T>" でも "ICollection<T>" でもバインドできた。
果たして "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 プロパティの内容は下記のとおりとなっている。
ここで環境変数 "SiteSettings:Tags:1:Text" に "Hoge" を設定すると、下記のとおり上書きされる。
上書き前の配列要素数を超えたら...?さて、では今回の例において、環境変数 "SiteSettings:Tags:999:Text" に "Hoge" を設定したらどうなるのか!? アプリ側で読み取った結果はこうなった。
一瞬戸惑ってしまったが、改めて JavaScript 脳になって考えてみると、何のことはない、環境変数名の "999" は「配列の添え字」ではなく、プロパティ名なのだ。 どうやら、ASP.NET Core のアプリケーション構成の仕組みは、バインド先の型がコレクションである場合、バインド元の値の "プロパティ" を列挙して、その値を順繰り、バインド先のコレクションの要素に編成しているようである。 配列、じゃなくて、結局は Key-Value の辞書であるなので、数字だけじゃなくて、任意の識別子を当てはめられる。 例えば環境変数名を、"SiteSettings:Tags:999:Text" ではなく、"SiteSettings:Tags:FizzBuzz:Text" としても、結果は同じになるのだ。 また、環境変数からの上書きというのではなく、appSettings.json の記述そのものを辞書形式で記述することもできる。
は、アプリケーション構成的観点では以下のように記述してるのと同義と言える。 実際、アプリでの読み取り結果も変らなかった。
さらには、プロパティ名 (Key) は数字である必要すらない。 下記でも TagSetting[] にバインドされ、読み取り結果は変わりない。
ちなみに、上記のような感じで Key-Value 辞書オブジェクトをコレクションにバインドした場合、その要素の追加順序は、プロパティ名 (Key) のオーダーとなるようだ。 削除はできなさそうなお、このような仕掛けであるようなので、appSettings.json で設定した配列構成要素を、appSettings.Develop.json や環境変数から "削除" することはできなさそうだ。 例えば今回の例において、appSettings.Develop.json を以下のとおり記述し、Tags の設定内容を要素数 0 件に潰そうとしたとする。
しかしこれは意図したとおりには動作しない。 配列ではなく、"0" や "1" といった配列序数を名前としたプロパティを持つオブジェクトを "上書き" するのだ、と JavaScript 脳で考える必要がある。 JavaScript で言うならば、オリジナルの Tags オブジェクト に対し、空のオブジェクトで Object.assign するようなものだ。
結果として、上記 appSettings.Develop.json は、何の効果ももたらさないこととなる。 そう、JavaScript の Object.assign を知っているならば、ASP.NET Core アプリケーション構成の "上書き" の仕組みは、Object.assign であると考えると間違いがないだろう。 まとめ以上、ASP.NET Core のアプリケーション構成の上書き (というか、"合成") の振る舞いについて色々試した結果となる。 ざっくりおさらいすると下記のとおり。
あと、最後になってしまったが補足しておくと、ここまでのアプリケーション構成の仕組みは ASP.NET Core アプリに限らず、Microsoft.Extensions.Options でアプリケーション構成を扱う .NET アプリ全てに適用される。 今回の投稿はかなりの大作となってしまった。 これでアプリケーション構成の "上書き" で迷うことはなくなった...と思いたい。 ▲
by developer-adjust
| 2018-09-28 23:29
| .NET
|
Comments(0)
2018年 06月 29日
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 リダイレクト機能込みでプロジェクトを作成する選択肢が用意されている。 ![]() こうして作成した ASP.NET Core 2.1 Web アプリの Startup.cs を覗いてみると、Configure メソッド内にて、「app.UseHttpsRedirection()」というように、HttpsRedirection ミドルウェアの組み込みを行っている行があるのがわかる。 ![]() この状況で、ローカル開発環境で実行してみると、たしかに http://localhost:... のアクセスは https://localhost:... へのアクセスにリダイレクトされている。 ![]() Azure Web Apps 上では、デプロイするだけでは NGそれではこの ASP.NET Core 2.1 Web アプリを Azure Web App に発行してみたらどうなるか。 残念ながら (?)、それだけでは HTTPS プロトコルへのリダイレクトは機能しない。 ![]() ドキュメントを確認してみると、HttpsRedirect ミドルウェアによる HTTPS プロトコルへのリダイレクトは、ある一定の条件が必要らしい。 ここでは、「環境変数 ASPNETCORE_HTTPS_PORT に、HTTPS プロトコルで接続するときのポート番号が指定されている場合」を、Azure Web Apps に適用して、HTTPS プロトコルへのリダイレクトが発動するように試してみた。 具体的には、Azure ポータル上から、当該 Web App のアプリケーション構成の設定ブレードを開き、下図のように HTTPS_PORT = 443 (※ポート番号 443 は HTTPS プロトコルの標準のポート番号) に設定する。 ![]() こうすると、Azure Web Apps 上に発行後でも、HTTPS プロトコルへのリダイレクトが機能するようになった。 ![]() 以上! ▲
by developer-adjust
| 2018-06-29 19:02
| .NET
|
Comments(0)
2018年 02月 27日
シナリオ.NET 版 Web アプリサーバー側フレームワークである ASP.NET Core で実装したWebアプリにおける、サーバー側からもクライアント側への呼び出しを行なうことのできる "Real time Web" 実装、ASP.NET Core SignalR。 今回はその ASP.NET Core SignalR を使っていて遭遇したトラブルとその回避方法の話である。 下記記事のコード例を基に話を進めよう。 但し、上記記事のコード例では、単一文字列を送受信していたところを、文字列の配列に変えてみたのが、今回のテーマ。 サーバー側実装は、上記記事のコード例に対し、下記強調表示のとおり書き換える。
すなわち、クライアント側からサーバー側へ送信された文字列の配列を、そのまま文字列の配列のまま、クライアント側に送り返す実装だ。 クライアント側も同様に下記要領で、SignalR 接続が開設したら、単一文字列 "Hello" を送信していたところを、["Hello", "World"] の文字列の配列を送信するようにする。 且つ、受信した内容を console.log で開発者コンソールに表示する際に、合せてその受信内容の型も表示するようにしてみる。
さて、このように手を加えたサンプルコードを実行、ブラウザで開くと、サーバー側からクライアント側に送信された内容が開発者コンソールに表示される。 その内容の期待値は、文字列の配列を送受信しているわけだから、当然下記のようなものとなる。
ところが実際にやってみると、その実行結果は下記のとおりとなった。
サーバー側からは文字列の配列をクライアント側へ送信しているのに、それを受け取ったクライアント側では、なぜか第1要素のみが受信ハンドラの引数に渡されているのである。 これはおかしいと、ブラウザの開発者コンソールにて通信内容を確認してみた。 すると、なんと、下図(蛍光マーカー表示の箇所)のとおり、サーバー側からは単一文字列が2引数で送信されているように見える。当方の期待するところとしては、ここは ["Hello", "World"] ではなく、[ ["Hello", "World"] ] である。 ![]() 原因原因は、サーバー側実装にあった。 SignalR における、サーバー側からクライアント側への送信に用いる InvokeAsync メソッドなのだが、これが可変個引数を扱うために object[] を引数にとるようになっている (下記)。
このため、愚直に配列をクライアント側へ送信しようと思って InvokeAsync メソッドの第二引数に渡すと、 配列を引き渡したいつもりが可変個引数として扱われてしまっていた という訳だ。 ちなみに、InvokeAsync メソッドには拡張メソッドによるオーバーロードバージョンも用意されている (下記)。
このオーバーロードバージョンによって、n 個引数での InvokeAsync 呼び出しの際、 InvokeAsync("method", new object[]{ "taro", 24 })と書かずに InvokeAsync("method", "taro", 24)と略して書けるようになっている。 回避方法回避方法はいくつかある。 「可変個引数のうち、第一引数に、文字列の配列を渡しますよ」ということを、略記せずにきっちり記述することで回避できる。
いちばん直球勝負で正直な実装方法だが、ちょっとくどい。 あるいはまた、「object[] args」のシグネチャにマッチするのを回避しつつ、クライアント側 JavaScript では配列として扱われる List<T> に変換してから渡す方法もある。
いったん List<T> を生成するのでメモリ効率的に気持ち悪いが。 はたまた、「object[] args」のシグネチャにマッチしなければよいので、InvokeAsync(string, object arg1, object arg2) などにマッチするよう、ダミーの引数を付加することもできよう。
しかし、前者でさえ「なぜわざわざ List<T> にするの?」という点で可読性低いのに、このダミー引数版はさらに可読性ダダ下がりな感じで、個人的には採用したくない手法。 「object[] args」のシグネチャにマッチしないようにオーバーロードバージョンの使用を誘導するのであれば、as 演算子で型を指定することもできる。
クライアント側実装もあわせて変えてよければ、同じく「object[] args」のシグネチャにマッチしないよう、匿名型オブジェクトにくるむ方法もある。
クライアント側はこうなる。
ざっと思いつく回避方法はこんなところだ。 ちなみに可変個引数は、例えば string.Format メソッドとかをはじめ、いろいろなところでよく使われる一般的な技法ではある。 ただ、例えば string.Format では配列を書式化したいとかいう需要がさほどないであろうから、そんな感じであまり問題にはならないのだろう。 まとめ以上、こんな感じで回避はできる。 とはいえ、やっぱり「なんでそのまま引数に渡さずにコネコネしてるの?」というように可読性は低いし、将来の保守で壊してしまったり、あるいは新規実装でもたびたびこのワナに陥りそうでちょっと嫌ではある。 ということで、この件は GitHub 上の Issue でもちょうど検討中らしい。 ASP.NET Core SignalR は、まだ Alpha バージョンである。 この件に関しても今後、何かしら変更や改善など進展が見られるかもしれない。 注目しておこうと思う。 ▲
by developer-adjust
| 2018-02-27 12:39
| .NET
|
Comments(0)
2017年 10月 30日
ASP.NET Core SignalR とはC# などの .NET 言語で実装する Web アプリのフレームワークである ASP.NET。 その ASP.NET フレームワーク上で、ブラウザ~サーバー間のリアルタイム双方向通信を実現するライブラリが SignalR である。 Node.js でいうところの Socket.IO に相当する、といえば話のとおりが良いだろうか。 (※もっとも、両者はそれぞれの思想や特性があるのであまり似てはいないとのこと。サーバー側からブラウザ側へ "プッシュ" する機能をカバーするという点で類似のライブラリとして話題にされるようだ。) その SignalR だが、ASP.NET の新世代である ASP.NET Core 版もちゃんと存在する。 ただ、この記事を書いている時点では、ver.1.0.0 Alpha2 リリース最終版というバージョンが、プレリリース版として公開されているのみ。 まだ正式の初版リリースには至っていない。 Alpha1 から Alpha2 に更新されたときも、若干の破壊的変更があったようで、いかにもまだ Alpha 段階という感じ。 そんな αバージョン時点での、ASP.NET Core SignalR のお話。 ASP.NET Web API から SignalR への連携SignalR を使った Web アプリを実装しているときに、サーバー側とクライアント側との間の通信技術が SignalR 一択である場合は、とくに困ることなく教科書どおりに実装すればよい。 しかし時折、その同一 Web アプリ上で、任意の HTTP クライアントに対する公開 Web API を搭載したい、なんてことがある。 で、えてして、その Web API で何やらが POST されたら、SignalR 経由で他のクライアントにプッシュ通知したい、なんて話になったりする。 さて、ASP.NET (ASP.NET Core じゃないほう) 時代、Web API の実装にあたっては、ASP.NET WebAPI が提供する ApiController クラスの派生クラスで API コントローラクラスを実装する。 Web API の要求は、この API コントローラクラスのメソッドに紐づけられる寸法だ。 ということで、Web API への POST を、SingalR によるプッシュ通信につなげるには、(POSTを受け付ける) API コントローラクラスのメソッド内で、SignalR における Hub クラスのコンテキストを手に入れる必要がある。 これを実現するには、下記のように書けば OK だ。
すなわち、ASP.NET SignalR が提供する GlobalHost クラスの ConnectionManager という静的プロパティを経由して、Hub コンテキストを入手可能という仕組みだ。 静的プロパティは、少なくともスコープの観点では事実上のグローバル変数のようなものだろう。 それでどんなシチュエーションからでも参照・入手可能ということになる。 ちなみに他にも、"HubController<T> を使う" という技法もあるらしい (2013年の記事だが、下記参照)。 ASP.NET Core SignalR からは GlobalHost クラスは廃止...と、まぁ、ここまでは ASP.NET Core じゃない、元祖(?) ASP.NET における話。 実は ASP.NET Core 上の SignalR では、GlobalHost クラスは廃止された模様だ。 では ASP.NET Core の SignalR において、"API コントローラクラスのメソッド内から SignalR でのサーバー側からのプッシュ送信" を行うにはどうしたらよいか? ASP.NET Core では、単純に、コントローラクラスのコンストラクタ引数に必要とするサービスインスタンスを渡してくれる、"DI (Dependency Injection, 依存性注入)" の仕組みで、任意の Hub のコンテキストが手に入る。 すなわち、コントローラクラスのコンストラクタの引数に、使用したい Hub コンテキスト型の引数を設けておけば、それだけで、ASP.NET Core MVC がそのコントローラクラスをインスタンス化するときに、その Hub コンテキストをコンストラクタ引数に入れてくれるのだ。 あとはコンストラクタに引数として渡された Hub コンテキストを、コントローラ自身のプロパティにキャッシュしておいて、アクションメソッド内から利用すれば OK だ。 具体的には下記コードとなる。
SignalR の Hub コンテキストだけ特別扱いということなく、他の各種サービスインスタンスと同じように、DI の仕組みで参照が手に入るのは、すっきりしていて覚えやすい。 また、かつての ASP.NET SignalR における GlobalHost.ConnectionManager のような static プロパティ = 実質のグローバル変数を参照することがなくなったので、単体テストもより書きやすくなる。 Web API コントローラクラス"以外"からの SignalR 連携さてところで、Web API のコントローラクラスではなく、もっとほかのトリガーをもとに SignalR のサーバー側からクライアント側へのプッシュ送信を行うにはどうしたらよいだろう? 例えば ASP.NET Core をセルフホスティングしたプロセス上で、GPIO ピンに対する入力を監視し、入力に変化があったら SignalR でクライアントに通知する、などの実装である。 先述のとおり、(ASP.NET Core じゃない) ASP.NET SignalR では、事実上のグローバル変数 = GlobalHost.ConnectionManager をどこからでも参照できてた。 それで上記例のような案件でも GlobalHost.ConnectionManager 経由でクライアントへのプッシュ送信が記述できた。 しかし ASP.NET Core の SignalR では、既に説明したとおり、GlobalHost.ConnectionManager のような実質のグローバル変数は、もう存在しない。 ではどうするか? 私が思いついたのは、ASP.NET Core の DI の仕組みで任意の Hub クラスのコンテキストが手に入るのだから、きっと ASP.NET Core の DI の仕組みに乗っかればいいはず、というアイディアだ。 ただ残念なことに、現時点の私の知識・技量では ASP.NET Core における DI の仕組みに疎い。 ASP.NET Core MVC がコントローラクラスのインスタンス生成をどうやってるか、同じことを自分のコードで真似するにはどうしたらよいか (先の例でいうと、GPIO の監視をつかさどるクラスを new するときに、どうやって依存性の注入を行うのか) がわかってないのだ。 それでも自分がわかっている範囲で、そこそこの解決策はある。 ASP.NET Core におけるエントリポイント、Startup クラスにおいて、アプリ起動時に呼び出される Configure() メソッドの引数に渡される IApplicationBuilder オブジェクトを参照すれば、DI の仕組みで注入可能なサービスインスタンスを入手可能である。 ということで、Startup クラスの Configure() メソッド内で下記のとおり実装すれば、任意の Hub コンテキストの参照を入手可能だ。
こうして入手した Hub コンテキストを、目的のオブジェクトに何らかの手段で引き渡せば OK だ。 (先の例でいえば、この Configure メソッド内で GPIO 監視クラスを new し、そのコンストラクタに Hub コンテキストを引き渡す設計にする、などの実装が考えられる) まとめASP.NET Core 時代の SignalR では、"DI (Dependency Injection, 依存性注入)" の仕組みで、Hub コンテキストを入手可能だ。 特に ASP.NET Core MVC/Web API コントローラクラスであれば、そのコンストラクタに IHubContext<T> 型の引数を用意すれば、そのコントローラクラスがインスタンス化 (new) されるときに、このコンストラクタ引数に T 型の Hub のコンテキストが渡される。 ASP.NET Core の DI の仕組みに乗っかれない場合でも、最悪、Startup の Configure() メソッドのタイミングで、IApplicationBuilder オブジェクト経由で、任意の Hub コンテキストを入手可能だ。 ▲
by developer-adjust
| 2017-10-30 22:29
| .NET
|
Comments(0)
2017年 09月 22日
ASP.NET Core 2.0 から使えるようになった "Razor Pages"ASP.NET Core 2.0 には、"Razor Pages" と呼ばれる、サーバーサイドレンダリングの Web アプリ実装方法が追加された。 詳しくは下記動画の 0:56:00 あたりからを視聴するとよいかも。 この Razor Pages、いろいろと面白いのだけど、自分的には「ちょこっとだけ動的要素がある Web ページ」を作りたいときに、ただそれだけのために ASP.NET MVC のコントローラーとビューとを作るまでもなく、"Razor Pages" として ~/Pages フォルダに "なんちゃら.cshtml" を置けば済んでしまうところが気に入った。 とくに ASP.NET Core MVC では、Web API 用とMVC用とのコントローラーの区別がなくなっており、Swagger UI で Web API のドキュメントページを自動生成させると、API 目的ではなく動的 Web ページのために設けたコントローラーも含まれてドキュメント自動生成されてしまう面倒があった。 (これを回避するために、Swagger ジェネレータでフィルタリングするコードを自前で書き足していた。) その点、その動的 Web ページが Razor Pages でシンプルに書いて済ませられるようであれば、この "混信問題" は解消するのが良いと感じた。 (Razor Pages は Swagger ジェネレータの対象にならないので。) シンプルに .cshtml を書ける? > じゃぁ markdown で!さてそんなシンプルな使い方もできる Razor Pages なのだが、さらにもっとシンプルに、.cshtml の内容を記述したくなった。 具体的には markdown 記法で書けないか、と考えた。 ということで用意してみたのが、AspNetCore.MarkdownPages だ。 この拙作 NuGet パッケージは、ASP.NET Core の HTTP 要求処理パイプラインに挟んでおくことで、応答ヘッダのコンテンツタイプが "text/markdown" だと、その応答コンテンツを markdown だと見なして HTML に変換してしまう、という "ミドルウェア" だ。 拡張子 .md な静的ファイルを配置しておいて、その .md ファイルを指す URL を開けば、AspNetCore.MarkdownPages が HTML に変換してブラウザに返信してくれる、みたいな使い方をする (下図)。 ![]() のであれば、Razor Pages 上でも markdown 記法で記述して、それを HTML 化してブラウザに返すようにできるはず、と考えた。 実際にやってみたAspNetCore.MarkdownPages のインストール・導入方法は、GitHub 上のドキュメントに譲るとして、 .cshtml 側の書き方を補足する。 最低限必要なのは、応答のコンテンツタイプを "text/markdown" に変更することだ。 一例としては .cshtml 中の冒頭のコードブロックで下記のように記述する。
もしも _Layout.cshtml などを併用してる場合は、
というように、共通レイアウトビューも外しておく。 以上で、あとはこの .cshtml 中に
とか書くと、ブラウザで表示したときに HTML 化して表示される。 ![]() "@DateTime.Now" の部分が、ちゃんと C# コードとして評価・実行されてレンダリングされていることもわかる。 オブジェクトの集合を foreach で列挙しての箇条書きはちょっと苦しくて、 (※下記例は、Razor Pages の機能での "ページモデル" に "Items" という List<string> なプロパティが生えている、というシナリオ)
というようにきれいに書いてはダメで、
というように、
という、インデントを潰した、どん詰まりな記述で書く必要がある。 ![]() しかし利用にはリスクも...以上、こんな感じで、Razor Pages を markdown 記法で記述することができた。 ただし、IDE/エディタは、.cshtml 内に markdown 記法で記述するとは想定していないはずで、コーディング支援やソース自動整形で難があるかもしれない。 そもそもの Razor ビューエンジンが、まさか markdown 記法でかかれたソースを読み込まされるとはつゆ知らずなわけで、Razor 構文と markdown 構文のはざまでレンダリング時の何か問題があるかもしれない。 また、拡張子 .md のファイルであれば、多くのエディタ/IDE では、HTML に変換後のプレビューを見ながら markdown をコーディングできることだろう。 しかし、おそらく拡張子 .cshtml では markdown プレビューしながらのコーディングは無理だろう。 さらには、現状の AspNetCore.MarkdownPages の機能上の限界であるのだが、実は、ページのタイトルや meta タグを制御することも難しい。 (markdown 記法はそういったメタ情報のことまでは範疇ではない...はず。) ...というように、Razor Pages を markdown 記法で書くのは若干微妙な感じも残る。 なお、ごくごく普通の Razor 構文で記述した .cshtml 中に、markdown 記法での記述を部分的に埋め込める Tag ヘルパーも見かけたような記憶もある。 そういったタグヘルパーライブラリを使ったほうが良いかもしれない。 それでもなお、この AspNetCore.MarkdownPages ミドルウェアと Razor Pages とを組み合わせることで、すっきりしたコーディングができる範疇のプロダクトであれば、これはこれで面白いかも、と思う次第。 ▲
by developer-adjust
| 2017-09-22 21:54
| .NET
|
Comments(0)
2016年 05月 31日
ASP.NET Core 1.0 ではアプリケーション構成は型付けされるASP.NET Core 1.0 からは、アプリケーション構成(オプション)を読み取る方法が大幅に改築された。まずはオプション値を表すクラスを記述し、そのオプション値の型にアプリケーション構成を逆シリアライズして、そうして生成されたオプション値を DI 機構を経由して受け取る、という "型付け" された形態になった。 詳しくは下記が大変参考になる。 ASP.NET Core 1.0 でオプションを柔軟に扱えるようになった話 http://blog.shibayan.jp/entry/20160529/1464456800 型がついてまわるので、文字列でアプリケーション構成のエントリ名を記述するのとは異なり、
※余談になるが、自分の場合、旧来の web.config 中の appSettings 構成セクションへのアクセスを静的型付けするために、SwissKnife.T4.AppSettings NuGet パッケージを多用してきた。 また、ASP.NET MVC コントローラクラスなどでは、DI 機構を通じてオプション値を入手するため、コントローラの単体テストの記述のしやすさに大きく貢献することだろう。 しかし実行時にエントリ名が決まることもあるこのように、ASP.NET Core 1.0 から型付けを前提にアクセスすることになったアプリケーション構成(オプション)。しかし、そうやたらとあるわけではないにせよ、まれに、実行時にエントリ名が決定されるような要件、言い換えると、文字列でエントリ名を指定してオプション値を入手しなければならないケースがある。 さきのしばやん先生のブログ記事でも触れられているが、"裏技的な感じ" はするものの、 IConfiguration を DI に追加すればこの要件に対応できると予想された。 ということで、試してみた。 IConfiguration を DI に登録してみるDI 機構にて注入される "サービス" オブジェクトを DI 機構に登録するには、Startup クラスの ConfigureServices メソッド内でその登録処理を行う。そこで、Startup クラスのコンストラクタにて別途 Configuration プロパティに初期化みの、IConfiguration インターフェースを備える "構成オブジェクト" を、ConfigureServices メソッド内で DI 機構に登録する。 具体的なコードは下記のとおり。 public void ConfigureServices(IServiceCollection services)以上で、ASP.NET MVC コントローラクラスなどで、コンストラクタ引数に IConfiguration 型の引数を記述しておくと、フレームワーク側にてこのコントローラクラスをインスタンス化するときに、先に DI 機構に登録されていた IConfiguration 型に対するオブジェクトが、この引数に渡される次第である。 具体的なコード例としては下記のとおり。 public class HomeController : Controllerこのコードを実行してみたところ、appsettings.json に「{"foo":"bar"}」が記述されていると、「this.Config["foo"]」は文字列 "bar" を返すことを確認できた。 このように、裏技感は否めないものの、実行時にエントリ名を示す文字列を組み立てて "動的" にアプリケーション構成を読み取ることが、DI 機構に IConfiguration オブジェクトを直接登録してしまうことで実現できた。 階層化されたオプションは?ところで、appsettings.json が以下のように記述されていた場合、{いちばん末端の "key2" エントリの値 ( この例では "bar" ) を IConfiguration インターフェース経由で読み取るにはどうすればよいか? 先の HomeController の例でいうと、 this.Config.GetSection("layer1").GetSection("layer2")["key2"]というコードで取得可能ではある。 しかしこれにはもっと簡易に書ける短縮構文があって、先の JSON の子要素をたどるのにコロン「:」でメンバ名を区切って記述すればそれでアクセス可能だ。 具体的には this.Config["layer1:layer2:key2"]で OK である。 GetValue 拡張メソッドも便利ここまでは IConfiguration のインデクサ構文でアプリケーション構成を参照していた。しかし参照方法としてはほかにもあり、「GetValue」という拡張メソッドも用意されている。 ここまでの例はすべて文字列としてアプリケーション構成を読み取っていたが、GetValue 拡張メソッドを使えば、
Microsoft.Extensions.Configuration 名前空間をインポート(using)すれば GetValue 拡張メソッドが使えるようになるので、いちどインテリセンスでどんなオーバーロードバージョンがあるのか眺めてみるのもよいかもしれない。 英字の大文字小文字は区別されない模様あと、これらアプリケーション構成(オプション)機構は、そのエントリ名に関して、大文字小文字を区別しないようだ。先の例でいえば、 this.Config["layer1:layer2:key2"]も this.Config["LAYER1:Layer2:kEY2"]も、同じ結果を返す。 これは型付けしたオプション用クラスについても同じで、オプション用クラスのプロパティ名と、appsettings.json に記載されているプロパティ名とが、英大文字小文字が違っていてもバインドされる。 まとめIConfiguration オブジェクトを DI 機構に登録することで、実行時にエントリ名文字列を構築してアプリケーション構成を読み取るような要件にも対応できることが確かめられた。一般的な用途では、基本的には型付けされたオプション機構を用いたほうが利が大きい。 とはいえ、場合・要件によってはここで紹介した技法も役に立つだろう。 以上、ご参考まで。 ▲
by developer-adjust
| 2016-05-31 22:47
| .NET
|
Comments(0)
1 |
ファン申請 |
||