手元のプロジェクトを移行していた際に、引っかかったのでメモとして残します。
何が起きたか
2.x系で動いていたコードがバージョンアップとともに実行時エラーが発生した ExpressionMetadataProvider の読み出し時になぜか読み出せなくなった
エラーになるコードは、以下のような感じ
public static IHtmlContent Sample<T, TProperty>(this IHtmlHelper<T> htmlHelper, Expression<Func<T, TProperty>> selector) { var metadata = ExpressionMetadataProvider.FromLambdaExpression(selector, htmlHelper.ViewData, htmlHelper.MetadataProvider); var defaultModelMetadata = metadata.Metadata as DefaultModelMetadata; return new HtmlString(""); }
具体的なエラーは、以下のような感じ
TypeLoadException: Could not load type 'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ExpressionMetadataProvider' from assembly 'Microsoft.AspNetCore.Mvc.ViewFeatures, Version=3.1.4.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'.
原因
ASP.NET Core 3.0 になったタイミングで、Microsoft.AspNet.*.Internal といった API群が本当の internal に変更された 今までは、public internal (pubternal) な API だったのでアクセスできたが、本当に Internal になったのでアクセスできなくなった。
対処法
HttpContext にアクセスできる場合、HttpContext.RequestServices を使って ModelExpressionProvider にアクセスできるので、以下のようにして対応
public static IHtmlContent Sample<T, TProperty>(this IHtmlHelper<T> htmlHelper, Expression<Func<T, TProperty>> selector) { var modelExpressionProvider = (ModelExpressionProvider) htmlHelper.ViewContext.HttpContext.RequestServices.GetService(typeof(IModelExpressionProvider)); var metadata = modelExpressionProvider.CreateModelExpression(htmlHelper.ViewData, selector); var defaultModelMetadata = metadata.Metadata as DefaultModelMetadata; return new HtmlString(""); }
まとめ
.NET Core のバージョンアップは、とても辛い