要約
以下が非常に詳しいです。
2022/07/21 追記: 日付を埋め込む場合は、次のmsbuildのProperty functionsを使ったやり方がよいでしょう。次のStackoverflowの回答もご覧ください。
メモ
例えばWebAPIやアプリケーションのメタ情報として今のバージョンやビルドした日時やGitのハッシュ値が欲しくなる時があります。
アップデート前後でアクセス数の変化を見たり、問題が入り始めた時にモジュールのバージョンやビルドの日時やコミットIDがわかると原因の特定がしやすくなります。
C#(.Net)ではAssemblyInfo
を利用すると色々埋め込んだり取得できるらしいですが、色々ある上に色々注意が必要でした。
Version
プロジェクトファイルを以下のようにします
<PropertyGroup>
<Version>1.2.3.4</Version> <!-- これを追加 -->
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
コードから読むときはこんな感じにします。クラス名はビルドで生成される成果物(dll等)に埋め込まれるクラス名にします。
// これはダメらしくnullになる
// string Version = typeof(Application).Assembly.GetCustomAttribute<AssemblyVersionAttribute>()?.Version;
// こうする
string Version = typeof(Application).Assembly.GetName().Version.ToString();
AssemblyVersionAttribute
で得られそうですが、nullになります。調べたところ、Assembly.GetName()
を使えとのことでした。
ToStringしていますが、Versionからはメジャーバージョン、マイナーバージョン等、細かく取ることもできます。
InformationVersion
string InformationVersion = typeof(Application).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
Version
が1.2.3.4
のとき、特に何もしていない場合はInformationVersion
も1.2.3.4
になります。
しかしdotnet build /p:SourceRevisionId=asdf
とすると、InformationVersion
は1.2.3.4+asdf
が得られるという感じです。
CIのビルド時にチェックアウトしてきたGitのCommitIdを入れたりするとよさそうです。最近のCIサービスはGitのCommitIDぐらいは環境変数に入ってきます。
ビルド日時とかは?
Assemblyにはないようです。以下の記事で見た感じ、いくつか方法がありそうです。
いくつかやり方はあるみたいですが、以下の2つを試しました。
- Assemblyのメタデータに埋め込んで取り出す
- リソースファイルとして埋め込む
Assemblyのメタデータに埋め込んで取り出す
多分これが一番楽だと思います。StackOverflowの記事でも回答についています
msbuildのProperty functionsなる機能のおかげで簡単な式を書けるので、これでビルド時に評価させて埋め込むことができます。
<ItemGroup>
<!-- 追加 -->
<AssemblyAttribute Include="System.Reflection.AssemblyMetadataAttribute">
<_Parameter1>BuildDateTime</_Parameter1>
<_Parameter2>$([System.DateTime]::UtcNow.ToString("o"))</_Parameter2> <!-- 2021-07-21T00:00:00.000000Z -->
</AssemblyAttribute>
</ItemGroup>
とやってビルドし、そのAssemblyに対して以下のようなコードを書けば読みだせます。
// AssemblyはAssemblyにあるクラスのTypeからリフレクションで取り出せます
// 例: var assembly = typeof(MyClass).Assembly;
public static string LoadBuildDateTime(Assembly assembly){
var metadata = assembly
.GetCustomAttributes<AssemblyMetadataAttribute>()
?.Where(a => a.Key == "BuildDateTime") // Key は _Parameter1 の値と合わせる
?.FirstOrDefault();
if (metadata != null)
{
return metadata.Value;
// ParseしてDateTimeで返す場合は以下
// return DateTime.ParseExact(metadata.Value, "o", CultureInfo.InvariantCulture);
}
return null;
}
リソースファイルを使うやり方
リソースファイルの埋め込み方は以下です。(厳密にバイナリが作られた日時ではないけど。)
- プロジェクトファイルにリソースファイルの場所を書く
- リソースファイルを用意する
-
Assembly.GetManifestResourceStream
を使って読み込む
プロジェクトファイルにリソースファイルの場所を書く
<Project Sdk="Microsoft.NET.Sdk.Web">
<!-- 中略 -->
<ItemGroup>
<EmbeddedResource Include="Properties/BuildDate.txt" /><!-- ここ追加 -->
</ItemGroup>
</Project>
リソースファイルを用意する。開発時はダミーでもいいのでこんな風に用意しておきます
1970-01-01T00:00:00,0000000000+09:00
Assembly.GetManifestResourceStream
を使って読み込む(実際は初回1回だけ読むとかしたほうが良いかもしれない)
private readonly string BuildDate = ReadStringFromResource("MyProjectNameSpace.Properties.BuildDate.txt");
private static string ReadStringFromResource(string resourceName)
{
using (var stream = new StreamReader(GetAssembly().GetManifestResourceStream(resourceName)))
{
return stream.ReadToEnd();
}
}
あとはProperties/BuildDate.txt
をCI時に作ってやればよいという感じです。