MS_NuGetCS0246 - NetDevInfraWGinOSSConsortium/NetDevInfraWiki GitHub Wiki

PackageReferenceに切り替え後のビルドで「error CS0246 The type or namespace name ...」が発生

概要

Package Referenceに切り替え後、
プロジェクトをMSBuildでビルドしようとしたら

  • CS0246 型または名前空間名 'xxxx' が見つかりませんでした。
    using ディレクティブまたはアセンブリ参照が不足しています。
  • CS0246 The type or namespace name 'xxxx' could not be found
    (are you missing a using directive or an assembly reference?)

が出た。

補足(症状の特徴): Visual Studio では通るのに、
コマンド ライン(MSBuild.exe)では落ちる
——というのが
本ページの症状の典型である。

Visual Studio      → ビルド成功
msbuild Foo.sln    → CS0246 が大量に出る

「型が見つからない」というメッセージから
ソースの問題と誤解しやすいが、実際は
パッケージの復元が行われていないことが原因である
(参照すべき DLL が存在しないため、型も見つからない)。

詳細

対策1

下記のような対策があったが、何れも効果は無かった。

  • 以下をインストールする。
Install-Package Microsoft.VisualStudio.Setup.Configuration.Interop
  • 以下の設定を追加する。
<PropertyGroup>
  <RestoreProjectStyle>PackageReference</RestoreProjectStyle>
</PropertyGroup>

.NET Standard.NET Coreだとバッチリ動いているが、
.NET Framework の方の実装は問題があるようなので、
.NET Framework 版は(、現時点では、)Package Reference
しない方がイイ。

補足(この結論は現在では見直してよい/最新化): 原文の
「.NET Framework 版は PackageReference にしない方がイイ」という結論は、
本ページの執筆時点(VS 2017 初期)では妥当だったが、
現在は状況が改善している

時期 状況
VS 2017 初期 packages.config からの移行が不安定。本ページの症状
VS 2017 15.7 移行ツールが搭載され、実用的になる
VS 2019 以降 packages.config は非推奨扱いに
現在 PackageReference が既定(新規プロジェクト)

現在は .NET Framework でも PackageReference が推奨である。
移行によって得られる利点は
NuGetでインストールすると依存関係が増えすぎる問題
NuGet を使用したパッケージ管理 の通りで、大きい。

ただし、移行できないケースは依然としてある。

阻害要因 内容
install.ps1 を持つパッケージ PackageReference では実行されない
web.config.transform 同上(設定が反映されない)
content\ でファイルを配るパッケージ contentFiles 未対応のものがある
古い SDK に依存するビルド環境 ビルド サーバーの更新が必要

RestoreProjectStyle は、
.csprojPackageReference が 1 つも無い状態で
PackageReference 方式として復元させたい」場合に使うプロパティで、
本症状の対処にはならない(原文の観測通り)。

対策2

nuget.exe restore を削除して、
MSBuild のオプションに以下を追加したら上手く動作した。

/t:Restore 

※ NuGetリストア(ビルドスクリプト)を nuget.exe ではなく、
MSBuild で行うように変更されていたというオチ。

補足(これが正解/仕組みの説明): 原文の「オチ」が
本質的な原因である。復元の担当が方式によって異なる。

方式 復元を行うもの 復元先
packages.config nuget.exe restore <sln>\packages\
PackageReference MSBuild の Restore ターゲット グローバル フォルダ + obj\project.assets.json
【PackageReference で必要なもの】
   obj\project.assets.json   ← 参照の解決表。これが無いと型が見つからない
   obj\Foo.csproj.nuget.g.props / .targets

   これらは MSBuild の Restore ターゲットが生成する。
   nuget.exe restore では(PackageReference 形式に対して)生成されない。

つまり、nuget.exe restore を呼んでいる CI スクリプトは、
PackageReference 移行後は機能しなくなる

Visual Studio は内部で Restore を実行するため気付かない——
というのが「VS では通るのに CI で落ちる」の正体である。

正しい書き方:

# ① MSBuild で復元してからビルド(.NET Framework も可)
msbuild Foo.sln -t:Restore
msbuild Foo.sln -t:Build -p:Configuration=Release

# ② 1 コマンドにまとめる(-restore スイッチ)
msbuild Foo.sln -restore -p:Configuration=Release

# ③ SDK スタイルなら dotnet で完結(restore は暗黙に実行される)
dotnet build Foo.sln -c Release

-t:Restore;Build のようにセミコロンで繋ぐのは避ける
復元で生成された .props / .targets
同一の MSBuild プロセスでは読み込まれないため、
結局同じエラーになる(別々に呼ぶ-restore を使う)。

ビルド スクリプトの整備は ビルドスクリプト も参照。

補足(切り分けの手順): CS0246 が出たら、まず次を確認する。

① obj\project.assets.json は存在するか?
      無い → 復元が走っていない(対策2)

② 存在するが古い(.csproj より古い)?
      → 復元が最新でない。obj\ を消して再復元

③ 存在し、最新。中に該当パッケージがあるか?
      無い → PackageReference の記述漏れ、または復元先ソースの問題

④ ある → 本当にソースの問題(using 漏れ、TFM 不一致)
# 疑わしいときは obj/bin を消してから復元し直す
Get-ChildItem -Recurse -Directory -Include obj,bin | Remove-Item -Recurse -Force
msbuild Foo.sln -restore -p:Configuration=Release

参考

NuGet/Home

dotnet/standard

Microsoft Learn


Tags: 移行, テスト, デバッグ, デプロイ, .NET開発

⚠️ **GitHub.com Fallback** ⚠️