ASP.NET MVC 5プロジェクトの依存NuGetパッケージを更新した際のトラブルシューティング

# 概要
- ASP.NET(無印) MVC 5（VB.NET）のプロジェクト（2015年頃に作られたもの）を改修する。
- システムの延命の為に.NET Frameworkを4.5.2→4.8にアップデート。
- ついでにNuGetパッケージの中から特に問題なさそうなものを可能な限り最新にアップデートして動作確認する。

上記の過程で起きた障害について、割と手間取ったものをピックアップしてまとめました。

ちなみに.NET Framework を4.5.2→4.8にアップデートすること自体は何もトラブルは起きませんでした。


# 各障害と対応

## Microsoft.CodeDom.Providers.DotNetCompilerPlatform を2.0.0から3.6.0にアップデート

同梱されるコンパイラのバージョンを最新のものにする為に、3.6.0にアップデートします。同梱されるコンパイラのバージョン毎の違いについてはこちらを参照してください。
https://github.com/dotnet/roslyn/blob/main/docs/wiki/NuGet-packages.md

###【障害】
ウェブサイト表示時にブラウザに以下のサーバーエラー表示。

> コンパイルエラー
> This compiler is provided as part of the Microsoft (R) .NET Framework, but only supports language versions up to Visual Basic 2012, which is no longer the latest version. For compilers that support newer versions of the Visual Basic programming language, see http://go.microsoft.com/fwlink/?LinkID=533241

日本語訳
> このコンパイラはMicrosoft(R) .NET Frameworkの一部として提供されていますが、Visual Basic 2012までの言語バージョンしかサポートしておらず、最新バージョンには対応していません。Visual Basicプログラミング言語のより新しいバージョンをサポートするコンパイラの情報はこちらを参照してください http://go.microsoft.com/fwlink/?LinkID=533241

リンク先をクリックすると、RoslynのGitHubページにジャンプします。

具体的なエラー発生箇所は、Viewの表示時に呼び出しているUrlヘルパーの内部で、VB14.0でサポートされた文字列への変数埋め込み機能を使っている場所でした。

###【原因】
ASP.NETではViewを運用中に動的にコンパイルする（例：hoge.vbhtmlをアップロードした後、サーバ側でそれをコンパイルする）オプションがあり、これはVisual Studio IDEの「公開」の設定から「ファイル公開オプション｜公開中にプリコンパイルする」をオフにすることで利用可能になります。

この機能を使う為には、当然ながらサーバ上にコンパイラが必要になりますが、これを担っているのが「Roslyn」という、Visual Studio 2015から採用された次世代コンパイラです。そしてこのコンパイラはIISには標準で搭載されていません。

このRoslynの環境を整えてくれるのが、Microsoft.CodeDom.Providers.DotNetCompilerPlatform パッケージです。
Roslynをサーバのbinフォルダにアップデートし、web.configのconpilersに自分自身をコンパイラとして登録します。（以前はこれ以外にもMicrosoft.Net.Compilersパッケージが必要だったようですが、バージョン2より不要になったようです）

参考：
http://surferonwww.info/BlogEngine/post/2016/05/10/problem-of-executing-roslyn-complier-for-aspnet-web-application-at-server.aspx

そして今回、DLLのバージョンが上がったのに、何らかの理由でWeb.Configの設定が古いバージョンを参照したままになっており、Roslynが機能していなかった為に古いコンパイラが使用され、上記のエラーが出たものと思われます。（普通にアップデートすればこの部分は自動的に更新されるはずなので、何かトラブルが起こったものと思われます）。

###【注意】
CodeDomなどのいくつかのキーワードで検索をすると、<system.codedom>のコンパイラ設定を消して、以下のようにせよという解決策がいくつかヒットします。

```XML:web.config（変更後）
  <system.codedom>
    <compilers />
  </system.codedom>
```

その上で、Visual Studioの「公開」設定から「ファイル公開オプション｜公開中にプリコンパイルする」をオンにすれば、エラーは出なくなる、というものです。

この方法で確かにエラーは回避できますが、Viewを運用中に動的にコンパイルする機能が失われます。
Viewの文字列をちょっと変更しただけでサイト全体の再コンパイルが必要になってしまいます。
それでよいケースもあると思いますが、多くの場合、問題があるでしょう。

###【対応】
web.configのMicrosoft.CodeDom.Providers.DotNetCompilerPlatformのバージョン番号を最新に合わせます。

```XML:web.config（変更前）
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>
```

```XML:web.config（変更前）
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=3.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=3.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>
```

## Npgsqlを4.0.10から5.0.7にアップデート
アップデートは必須ではなさそうですが、コミットログを見ると多くのバグフィックスが含まれており、将来の問題発生を未然に防ぐ意味で、この機会にアップデートを行います。

###【障害】
DB接続直前に以下の例外が発生。

> 「要求された .Net Framework データ プロバイダーが見つかりません。これは、インストールされていない可能性があります。」

###【原因】
Npgsql.dllのバージョンが上がったのに、Web.ConfigのDbProviderFactoriesの設定が古いバージョンを参照しています。

###【対応】
web.configのNpgsqlのバージョンを最新に合わせます。

```XML:変更前
  <system.data>
    <DbProviderFactories>
      <remove invariant="Npgsql"/>
      <add name="Npgsql Provider" invariant="Npgsql" description=".NET Framework Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql, Version=4.0.10.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7"/>
    </DbProviderFactories>
  </system.data>
```

```XML:変更後
    <DbProviderFactories>
      <remove invariant="Npgsql"/>
	  <add name="Npgsql Provider" invariant="Npgsql" description=".NET Framework Data Provider for PostgreSQL" type="Npgsql.NpgsqlFactory, Npgsql, Version=5.0.7.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7" />
    </DbProviderFactories>
  </system.data>
```

## HTML部品関連のJS/CSSライブラリをアップデート

###【障害】
特に大きくバージョンを上げたわけでもないのに見栄えが微妙にずれる。

###【原因と最初の対応】
パッケージに含まれるCSSファイルをプロジェクト側で直接変更しており、アップデート時に上書きされて元に戻ってしまっています。
そこで、CSSを直接修正するのではなく、追加のCSSファイルを作成し、変更したい箇所のみ別途スタイルを上書き指定する形にし、BundleConfig.vbのバンドル設定にて、元となるCSSの直後に追加しました。

```vb:BundleConfig.vb
bundles.Add(New StyleBundle("~/Content/xxx_themes/css").Include(
               "~/Content/xxx_themes/core.css",
               "~/Content/xxx_themes/dialogs.css",
               "~/Content/xxx_themes/dialogs_customize.css"))	'追加したファイル
```

###【追加の障害】
CSSの読み込み順が、bundlesに追加した順にならず、dialogs.cssの前にdialogs_customize.cssが読み込まれてしまう。
その為、dialogs_customize.cssの意味がない。

###【原因】
bundles設定はそもそも、読み込み順が保証されないもののようです。
順番に読み込まれてくれないと困る気がするのですが…。

###【対応】
StyleBundleクラスには.Ordererというプロパティがあり、ここにIBundleOrdererインタフェースを実装したクラスを指定することで、バンドル後のCSSの並び順を指定できるようです。

以下のクラスをBundleConfig内に定義し、指定するようにしたところ、指定した順序通りバンドルされるようになりました。

```vb
    Private Class AsIsBundleOrderer
        Implements System.Web.Optimization.IBundleOrderer

        Public Function OrderFiles(context As BundleContext, files As IEnumerable(Of BundleFile)) As IEnumerable(Of BundleFile) Implements IBundleOrderer.OrderFiles
            Return files
        End Function
    End Class
```

```vb:BundleConfig.vb
bundles.Add(New StyleBundle("~/Content/xxx_themes/css") With {.Orderer = New AsIsBundleOrderer()}.Include(
               "~/Content/xxx_themes/core.css",
               "~/Content/xxx_themes/dialogs.css",
               "~/Content/xxx_themes/dialogs_customize.css"))	'追加したファイル
```

参考：
https://stackoverflow.com/questions/11979718/how-can-i-specify-an-explicit-scriptbundle-include-order