VSCode+.Net Coreで依存プロジェクトが依存しているパッケージが参照できないエラー(CS0012)になるときはパッケージの復元を行うと解消するかもしれない

要約が苦手ですみません。

要約
------------

あるプロジェクトが依存しているパッケージについて、プロジェクトを参照する別プロジェクトから参照できず、以下のようなコンパイルエラーになることがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/52527/00cbf8c8-588d-d2c7-de81-7d54d0adae0b.png)

> 型 'DbSet<>' は、参照されていないアセンブリに定義されています。アセンブリ 'Microsoft.EntityFrameworkCore, Version=5.0.10.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' に参照を追加する必要があります。 [MyLibrary.Tests]csharp(CS0012)

この時にはまず、`dotnet restore` (パッケージの復元) を試みると良いかもしれません。特にコマンド操作でパッケージ追加している場合は忘れがちなので起きやすいかもしれません。
改善しない場合は、LSP(Omnisharp)サーバの再起動、もしくはIDE(VScode)の再起動を行うと良いかもしれません。

改善しない場合は、参照が漏れているか設定不備だと思いますが、本記事ではそこはカバーしません。適宜対処しましょう。

CS0012のコードについては以下のドキュメントにも書いてあるんですが、この事象に限らずSDKやバージョンに指定不備などでも起きるようなので、地道にやっていくことが大事でしょう。

https://docs.microsoft.com/en-us/dotnet/csharp/misc/cs0012


### 再現手順

``` bash
# 作業ディレクトリに移動
mkdir work
cd work

# ライブラリ用のプロジェクトを作成
dotnet new classlib -n MyLibrary
# ライブラリのテストプロジェクトを作成
dotnet new xunit -n MyLibrary.Tests

# 依存プロジェクトを追加
dotnet add MyLibrary.Tests reference MyLibrary

# ソリューションファイルの作成とプロジェクトの紐づけ
dotnet new sln
dotnet sln add MyLibrary
dotnet sln add MyLibrary.Tests

# ソリューションに対してリストアが行われるので、パッケージは最新の状態になる
dotnet restore

# その後、MyLibraryプロジェクトに適当なパッケージ追加する
dotnet add MyLibrary package Npgsql.EntityFrameworkCore.PostgreSQL

# 追加したのでrestoreを行い、
dotnet restore MyLibrary

# MyLibrary.Tests プロジェクトに対するRestoreを忘れている。行わないと上記のエラーになるはず。

# この場合、以下を行うと解消するはず
dotnet restore MyLibrary.Tests
```

この手順で作ったファイルは以下です。
https://github.com/fukasawah/sandbox-cs0012-forgot-restore

が、このバージョン管理しているファイルは悪くはないはずなので、clone後にdotnet restoreした状態であれば正常にビルドができるはずです。問題は依存しているプロジェクトの依存パッケージが変わっているのにrestoreをしていない場合かと思います。




背景
----------------

例えば、MyLibrary プロジェクトのコードをテストするMyLibrary.Tests プロジェクトを作ろうとします。
このとき、MyLibrary プロジェクトはEntityFramework Coreパッケージに依存していますが、パッケージはなんでもよいです。MyLibrary.Tests プロジェクトからは間接的に何らかのパッケージに依存しているという状態です。

```
(依存パッケージ)
↑
MyLibrary プロジェクト
↑
MyLibrary.Tests プロジェクト
```

MyLibrary.Tests プロジェクトのプロジェクトファイル(.csproj)にはMyLibrary プロジェクトの参照のみを含めます。`dotnet add MyLibrary.Tests reference MyLibrary`とかで追加するとこうなります。

``` MyLibrary.Tests/MyLibrary.Tests.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <ItemGroup>
    <ProjectReference Include="..\MyLibrary\MyLibrary.csproj" /> <!-- MyLibrary プロジェクトの参照 -->
  </ItemGroup>

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
</Project>
```

MyLibrary プロジェクトで定義しているMyDbContextクラスはEntityFramework Coreのお作法に従い、`public DbSet<Blog> Blogs`プロパティ持っています。それをMyLibrary.Tests プロジェクトから参照しようとしました。

```
var context = new MyDbContext();
var m = context.Blogs;
```

すると、`Blogs`の参照の箇所で以下のようなエラーになりました。

```
型 'DbSet<>' は、参照されていないアセンブリに定義されています。アセンブリ 'Microsoft.EntityFrameworkCore, Version=5.0.10.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' に参照を追加する必要があります。(CS0012)
```

MyLibrary プロジェクトの依存関係を芋づる式に解決していればできるはずで、同様な状況で過去にテストプロジェクトを書いたときは引っかからなかったので、このエラーがなぜ起きたのかがわかりませんでした。

この際、MyLibrary プロジェクトはビルドが可能な状態でありました。


回避策
-----------

結局よくわかっていませんが、`dotnet restore`で生成される `obj/project.asset.json` あたりのファイルがないor適切な状態になっていないとこのエラーになるようでした。事象が起きたときは、MyLibrary.Tests プロジェクトには「`MyLibrary.Tests/obj/project.asset.json`」が存在しない状態でした。

なので、この状態になったときは明示的に `dotnet restore`（パッケージの復元） を行うとよさそうです。
すると、このファイルが生成され、Omnisharpが自動的にこのファイルを検知し、解消してくれるはずです。

なお、参照設定が不足している場合は、そもそも「型または名前空間の名前 'XXXXX' が見つかりませんでした (using ディレクティブまたはアセンブリ参照が指定されていることを確認してください) （CS0246）」や「型または名前空間の名前 'YYYYY' が名前空間 'XXXXX' に存在しません (アセンブリ参照があることを確認してください)（CS0234）」のエラーが多発するはずです。この場合は単純に参照を足せば解消するはずです。


なお、Omnisharp自体の挙動がおかしくなることがあるので、もしくはVSCodeから再起動（`Ctrl+P`→`>Omnisharp: Restart Omnisharp`）、もしくはVSCode自体の再起動を行うと良いです。


ずっと設定ファイルが悪いと思ってコマンド操作をせず設定ファイルとにらめっこしていたので備忘録です。
単純に忘れずにやりましょうとか、できることをやっておきましょうとか、VisualStudioなら起きないよとか、普通は引っかからない話のような気もします。