tech.guitarrapc.cóm

Technical updates

.NET Core で AssemblyInfo.cs の生成を制御する

C# のアセンブリ情報は AssemblyInfo.cs によって制御されています。 .NET Core でいくぶん取り扱いが変わったものの基本は一緒です。

たびたび忘れるので、どのように取り扱いが変わったのか制御方法をメモしておきます。

目次

TL;DR

  • .NET Core で AssemblyInfo.cs はビルド時に自動生成されるようになりました。
  • csprojにGenerateAssemblyInfoを指定することで自動生成自体を止めたり、GenerateAssemblyXxxxxAttributeを指定することで特定属性の出力を止めることができます。
  • 出力を上書きたいときは、上書きたい属性だけ制御するようにして予期せぬ副作用は回避しましょう。

Microsoft.NET.GenerateAssemblyInfo.targets

AssemblyInfo は、.NET Framework まではProperties/AssemblyInfo.cs として存在していましたが、.NET Core SDK ベースのcsproj ではビルド時に自動生成されるようになりました。

この自動生成を制御しているMSBuildのタスク Microsoft.NET.GenerateAssemblyInfo.targets を見つつどのように行うか見ていきましょう。

sdk/Microsoft.NET.GenerateAssemblyInfo.targets at master · dotnet/sdk

AssemblyInfo の自動生成をなぜ制御するのか

自前でAssemblyInfoを生成しようとしたときに、属性が重複してビルドできなくなるためです。

例えば、.NET Core の適当なプロジェクトを作って次のようにアセンブリのバージョンを任意の値で制御しようとするとエラーが起こります。

gist.github.com

エラーは次の通りです。

Error CS0579 Duplicate 'System.Reflection.AssemblyVersionAttribute' attribute

このような時に、AssemblyInfo の出力を制御したくなります。

AssemblyInfoの自動生成を止める

dotnet core のプロジェクトでビルドをすると、obj フォルダの中にASSEMBLYNAME.AssemblyInfo.cs が自動生成されます。 ASSEMBLYNAME は、デフォルトではプロジェクト名ですがご存知の通り指定もできます。(ここでは省きます)

先ほどの Microsoft.NET.GenerateAssemblyInfo.targets から、次の属性で制御されていることがわかります。

<PropertyGroup Condition="'$(GenerateAssemblyInfo)' == 'true'">

AssemblyInfo の自動生成を止めたいプロジェクトのcsproj に次の要素を書くことで、objに生成されなくなります。

<PropertyGroup>
  <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>

例えば先ほどのConsole アプリのcsproj を編集してみましょう。(上:編集前 Before.csproj / 下:編集後 After.csproj)

gist.github.com

これでAssebly属性の重複によるビルドエラーが解消して、ビルドができるようになりました。 先ほどまであったConsoleApp2.AssemblyInfo.cs が obj フォルダに生成されなくなったことが確認できます。

f:id:guitarrapc_tech:20190430202802p:plain
obj の中を見るとConsoleApp2.AssemblyInfo.cs がないことが分かる

ただし、AssemblyInfo の自動生成を止めると副作用が大きいため推奨しません。

特に、ASP.NET Core や .NET Core で UserSecrets を使っている場合は、UserSecretsが機能しなくなります。 これは、UserSecrets が実行時にsecret のパスを参照するときにSecret Id はAssemblyInfo にビルド時に埋め込むようにしており、自動生成を止めるとUserSecrets の Id も参照できなくなるためです。

AssemblyInfo の特定の属性の生成を止める

先ほどのようにただバージョンを指定したものにするなら、AssemblyInfoは生成するけど、特定の属性をとめるほうが副作用がありません。 これは先ほどの Microsoft.NET.GenerateAssemblyInfo.targets から、次の属性で制御されていることがわかります。

gist.github.com

例えば、今回のようなAssemblyVersion 属性の重複なら、次の要素をcsprojに追加しましょう。

<PropertyGroup>
  <GenerateAssemblyVersionAttribute>false</GenerateAssemblyVersionAttribute>
</PropertyGroup>

これでAssemblyInfo の生成自体をとめることなくビルドできるようになります。 obj に自動生成された ConsoleApp2.AssemblyInfo.cs を見てみると、意図したとおり属性で指定したバージョンが埋め込まれていることがわかります。

gist.github.com