dotnet publish時にp:PublishSingleFileを指定した場合、設定ファイルも一緒にパッケージングする
単一ファイルで出力すると、ファイルサイズがデカいとか、起動が少し遅くなるとかありますが、ちょっとしたツールを配布するときはだいぶお手軽になります。
dotnet publish p:publishSingleFile=true
独自の設定ファイル(appsettings.json)のような単なるコンテンツファイルは、プロパティーウインドウで明示的にコピーされるようにしないと、パッケージに含まれてくれません。
この状態でビルドしても、出力フォルダーには設定ファイルは見当たりませんが、実行するとちゃんと設定ファイルを読んでくれます。
これは、単一ファイルで配布した場合、実行時に一時フォルダー(%LocalAppData%\Temp.net[exe名]\ハッシュのディレクトリ)に展開され実行されるからです。
このため、単にプログラムと同じディレクトリに設定ファイルを置いたとしても設定を読み込んでくれないので、publish時に環境毎の設定ファイルを含めてあげるか、Microsoft.Extensions.Configurationのパターンのように、環境変数やコマンドライン変数から設定値を上書きできるように設計したほうが良さそうです。
EntityFramework Core 3.1 は .NET Standard 2.0をターゲットにしている
.NET Core 3.1 に合わせて EntityFramework Core の 3.1 もリリースされています。
下記の記事でも触れられているように、この子は .NET Standard 2.0 をターゲットにしているようなので、.NET Core 2.2 以下でも使えるようになっているんですよね。
Announcing Entity Framework Core 3.1 and Entity Framework 6.4
https://github.com/aspnet/EntityFrameworkCore/issues/18141
ただ、うちで採用しているPomelo.EntityFrameworkCore.MySqlは.NET Standard 2.1をターゲットにしているので、こちらに引きずられちゃうんですけれどね、、、
https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql
Razorlight の .NET Core 3.x 対応
テキストのテンプレートエンジンとしてRazorlight(https://github.com/toddams/RazorLight)のbeta1を利用しています。.NET Core 3.1にアップグレードしたところ、下記のような例外が発生してRazorEngine の構成に失敗してしまいました。
InvalidOperationException: Cannot find reference assembly ‘Microsoft.AspNetCore.Antiforgery.dll’ file for package Microsoft.AspNetCore.Antiforgery
もともとbeta1を利用していたので、そろそろ正式版がリリースしている?とおもってプロジェクトサイトをのぞいてみたら、beta2で3.0に対応しているようなのでまずこいつのアップグレードをします(betaはとらない方針なのかな?nugetで出てこないから正式版にしてほしいけれど、、、)。
Razorlight v2.0.0-beta2 対応
betaリリースということなので、nugetの管理画面からインストールする場合は、プレリリースを含めるチェックボックスをオンにしてからインストールします。
TemplateCacheを使っているコードとCompileRenderAsyncの非ジェネリック版を使っていると文句を言われるので修正します。
TemplateCacheの対応
変更前
var cacheResult = _razorEngine.TemplateCache.RetrieveTemplate(templateKey); if (cacheResult.Success) {
変更後
var cacheResult = _razorEngine.Handler.Cache.RetrieveTemplate(templateKey); if (cacheResult.Success) {
CompileRenderAsyncのジェネリック対応
変更前
var text = await _razorEngine.CompileRenderAsync(templateKey, templateText, vm);
変更後
var text = await _razorEngine.CompileRenderStringAsync(templateKey, templateText, vm);
これでコンパイルエラーと警告は消えたんだけれど、まだ同じエラーが出る、、、
Cannot find reference assembly への対応
.NET Core 3.1の既知の問題を見ると一番上にそれっぽい記述が、Preview2で対応されたとなっているけれど、、、
https://github.com/dotnet/core/blob/master/release-notes/3.1/3.1-known-issues.md
とりあえず、プロジェクトファイルにこの2行を足してみると、RazorEngine の構成自体は無事通るようになりました。
<PreserveCompilationReferences>true</PreserveCompilationReferences> <PreserveCompilationContext>true</PreserveCompilationContext>
Razorlightが内部で使っているRoslyn向け言語バージョンの指定
実際にテンプレートからテキストの生成を行ってみると、こんな例外画面が!!
あれ?.NET CoreのプロジェクトってC#の言語バージョンは変更できなかったような、、、
…プロジェクトファイルに書いてありました!!7.3→8.0に変更したら、無事動きました。
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp3.1</TargetFramework> ... <LangVersion>7.3</LangVersion> ... <PreserveCompilationReferences>true</PreserveCompilationReferences> <PreserveCompilationContext>true</PreserveCompilationContext> </PropertyGroup> ... </Project>
Visual Studio Version 16.4.0のコンテナ用ツール
.NET Core 3.1 に合わせて Visual Studio 2019 の最新版である Version 16.4.0 が同時に公開されましたが、このバージョンに含まれるコンテナ用のツールが結構よさげです。Kitematicでもいいんですが、表示されている情報が古かったりして微妙なことが多いので結構いいかも。
ツールメニュー > その他のウインドウ > コンテナー から起動できるこの子ですが、
コンテナを起動したり、起動しているコンテナの環境変数やポート情報を確認したり、
ログを表示したり、
コンテナの中身のファイルして開いたり(!!)が簡単にできます。
残念ながらホストにファイルをコピーするなどは、ここからは行えないみたいですね。
必要になったらコマンドアイコンをクリックすれば、コマンドプロンプトが開きます。
統合ターミナル(Whack Whack Terminal)がインストールされていればそちらを起動してくれるみたいです。
Riderのコンテナツールもいい感じですよね
.NET Core 3.1 のリリース、12/23には.NET Core 2.2 がサポート終了
今日(2019/12/03).NET Core 3.1のアナウンスがありダウンロードが可能になりました。
Announcing .NET Core 3.1
下記のページに.NET Coreのサポートポリシーが記載されていますが、今回のリリースはLTS付きなので、少なくとも3年の長期サポートが付きます。
https://dotnet.microsoft.com/platform/support/policy
→ 3.1のリリースに間に合っていないようでこちらのほうが最新の情報が載っていますね。
https://github.com/dotnet/core/blob/master/microsoft-support.md
これ自体は喜ばしいことなんですが、現行リリースである2.2とひとつ前のLTSである2.1のサポート終了時期が迫っているということにもなります。下記の表のとおり、2.2は2019/12/23、2.1は2020/03/03までのサポートになります。
Docs Microsoftの移行に関するドキュメント
ASP.NET Core 2.2 から3.0 への移行
https://docs.microsoft.com/ja-jp/aspnet/core/migration/22-to-30
ASP.NET Core 3.0 から3.1 への移行
https://docs.microsoft.com/ja-jp/aspnet/core/migration/30-to-31
コミュニティーの移行に関するドキュメント
ASP.NET Core / Entity Framework Core 3.0 の気になった機能と 2.2 からの移行
ASP.NET Core 2.2→3.0への移行 メモ
ASP.NET Core + Entity Framework Core のプロジェクトを 2.2 から 3.0 にアップグレードした話
EventListener の OnEventSourceCreated メソッドはコンストラクター実行前に呼び出される
EventListenerを継承するクラスを作っていてはまったのでメモ
下記のようなコードは、コンストラクターが完了する前にOnEventSourceCreatedが呼び出されるのでNull参照で落ちます。
public class GcEventListener: EventListener { private readonly ILogger _logger; public GcEventListener(DiagnosticsConfig config, ILoggerFactory loggerFactory) { _logger = loggerFactory.CreateLogger(); } protected override void OnEventSourceCreated(EventSource eventSource) { _logger.Information("test"); } }
対策としては、githubのissueにある通り、OnEventSourceCreated で受け取ったイベントソースのリストをいったん変数に格納しておいて、コンストラクターに戻ってから有効化する。
https://github.com/Microsoft/ApplicationInsights-dotnet/issues/1106
.net core 3系のパフォーマンス系ツール
ASP.NET のメトリクスを取りたい場合、Windows 環境であればパフォーマンスカウンターが使えるんだけれど、Linux 環境では ASP.NET Core から利用できるパフォーマンスカウンターなんてものは無いので、dotnet-counters ツールを利用します。
https://docs.microsoft.com/ja-jp/dotnet/core/diagnostics/dotnet-counters
SDK がインストール環境であれば、インストールコマンドを入力してパスを通してあげれば利用できるようになります。
docker 環境で SDK が入っていないイメージをもとに Build している場合は、先に SDK をインストールする必要があります。例えば、Visual Studio が作成する Dockerfile で利用される buster-slim の場合は、下記の URL を参考に SDK をインストールする必要があります。
https://dotnet.microsoft.com/download/linux-package-manager/sdk-3.0.101
あらかじめ、dotnet-counters ツールを使うことがわかっているなら、Dockerfile を書き換えてしまってもいいかもしれません、、、
wget -qO- https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.asc.gpg sudo mv microsoft.asc.gpg /etc/apt/trusted.gpg.d/ wget -q https://packages.microsoft.com/config/debian/9/prod.list sudo mv prod.list /etc/apt/sources.list.d/microsoft-prod.list sudo chown root:root /etc/apt/trusted.gpg.d/microsoft.asc.gpg sudo chown root:root /etc/apt/sources.list.d/microsoft-prod.list sudo apt-get update sudo apt-get install apt-transport-https sudo apt-get update sudo apt-get install dotnet-sdk-3.0
dotnet-counters ツールをインストールするには下記のコマンドです。
# dotnet tool install --global dotnet-counters Tools directory '/root/.dotnet/tools' is not currently on the PATH environment variable. If you are using bash, you can add it to your profile by running the following command: cat <> ~/.bash_profile # Add .NET Core SDK tools export PATH="$PATH:/root/.dotnet/tools" EOF You can add it to the current session by running the following command: export PATH="$PATH:/root/.dotnet/tools" You can invoke the tool using the following command: dotnet-counters Tool 'dotnet-counters' (version '3.0.52901') was successfully installed.
インストールしたら、指示の通りパスを通してあげましょう。
実行するとこんな感じになります。
診断ツールに関しては、Docsの下記のURLに一通り乗っています。
https://docs.microsoft.com/ja-jp/dotnet/core/diagnostics/
dotnet-counters 以外にも、dotnet-dump、dotnet-trace といったツールもあるようです。
dotnet core 3.0 でマイグレーションスクリプトを追加するときは、dotnet-efサブコマンドを別途インストールする
dotnet core 3.0 を導入済みの端末で dotnet ef サブコマンドを実行すると、下記のようなエラーが表示されマイグレーションファイルが追加できない問題が発生しました。
指定されたコマンドまたはファイルが見つからなかったため、実行できませんでした。
次のような原因が考えられます:
* 組み込みの dotnet コマンドのスペルが間違っている。
* .NET Core プログラムを実行しようとしたが、dotnet-ef が存在しない。
* グローバル ツールを実行しようとしたが、プレフィックスとして dotnet が付いたこの名前の実行可能ファイルが PATH に見つからなかった。
下記のURLにある通り、dotnet core 3.0 からは dotnet-ef サブコマンドを別途インストールが必要になったようです。
dotnet tool install --global dotnet-ef
EF Core 3.0 に含まれる破壊的変更
EF Core のコマンドライン ツールである dotnet ef が .NET Core SDK の一部ではなくなった
https://docs.microsoft.com/ja-jp/ef/core/what-is-new/ef-core-3.0/breaking-changes#dotnet-ef
マイグレーションをdocker内で実行している場合もDockerfile内でインストールしないとこけるので注意ですね。
.net core 3.0 でデータプロバイダーにSQLiteを利用している場合、DateTimeOffset 列に対する OrderBy で例外が発生する
アプリのデータベースにはMySQLを利用しているんですが、単体テスト時はSQLiteを使ってテストしています。
こんな感じのコードを実行した場合、.net core 2.2の時点ではMySQL(Pomelo.EntityFrameworkCore.MySql)だろうが、SQLiteだろうが特に問題なく実行できていたのですが、
await MyDbContext.Users .OrderByDescending(u => u.UpdateDate) .FirstOrDefaultAsync();
.net core 3.0にアップデートした後に単体テストを実行したらこんな例外が発生してテストが失敗してしまいました。
メッセージ: System.NotSupportedException : SQLite cannot order by expressions of type 'DateTimeOffset'. Convert the values to a supported type or use LINQ to Objects to order the results.
このあたりの制約に引っかかっているようです。
SQLite EF Core データベースプロバイダーの制限事項
https://docs.microsoft.com/ja-jp/ef/core/providers/sqlite/limitations#query-limitations
検索してみるとこのあたりで良い感じの解決策がありました。
https://blog.dangl.me/archive/handling-datetimeoffset-in-sqlite-with-entity-framework-core/
OnModelCreatingのタイミングで、データベースプロバイダーがSQLiteの場合に型変換を実施して回避するようです。
C# 8で有効になったusingに対する複数の機能拡張
小規模なバッチプログラムを書く機会があって、折角だし dotnet core 3.0 で作成してみるかと実装していったところ、ReSharper にこんな指摘をされた。
おや?と思いつつ ReSharper さんに従ってみる。
もともとはこんなコードで、マルチパートなリクエストを送る処理ですね。
using (var fileStream = File.OpenRead(localTemplatePath)) using (var multipartContent = BuildSaveTemplateRequest(remoteTemplateName, fileStream, contentType, comment)) await CreateHttpClient().PostAsync($"/api/template/{remoteTemplateName}", multipartContent);
提案を受け入れると await using になりましたね。
非同期の using って何だろう?という感じですが、Docsのこの記事を見ると await がかかっているのは using というより var fileStream に対してなんですね。非同期ストリームは待ち望んでいた機能なのでワクワクですね。
チュートリアル: C#8.0 および .NET Core 3.0 を使用して非同期ストリームを生成および使用する
https://docs.microsoft.com/ja-jp/dotnet/csharp/tutorials/generate-consume-asynchronous-stream
await using (var fileStream = File.OpenRead(localTemplatePath)) using (var multipartContent = BuildSaveTemplateRequest(remoteTemplateName, fileStream, contentType, comment)) await CreateHttpClient().PostAsync($"/api/template/{remoteTemplateName}", multipartContent);
あれ?まだ提案がある?
docs.microsoft では Using 宣言 となっている改善機能ですね。
外側の変数スコープに応じて Dispose を呼び出してくれるようになるので、ソースの見通しが良くなります。
https://docs.microsoft.com/ja-jp/dotnet/csharp/whats-new/csharp-8#using-declarations
await using var fileStream = File.OpenRead(localTemplatePath); using var multipartContent = BuildSaveTemplateRequest(remoteTemplateName, fileStream, contentType, comment); await CreateHttpClient().PostAsync($"/api/template/{remoteTemplateName}", multipartContent);
ただ、この提案があるのはusingの後に何もない場合のみで、usingの後にそのリソース以外を使ったものがある場合は提案されないようです。
C#も構文が増えてきて、ちょっと目を離すとおや?これコンパイル通るのか?みたいなコードになりますが、ReSharperさんに支えられて何とかなっています。