使用Microsoft.AspNetCore.Mvc.ViewFeatures时遇TypeLoadException类型加载错误
你在ASP.NET Core项目中使用自定义HTML Helper生成Alert组件时,遇到了类型加载异常,相关代码及错误信息如下:
视图页面代码
@using MyHelpers @model FluentHtmlHelpers.Models.SampleAlertModel @{ ViewBag.Title = "Strongly Typed"; } <h2>Strongly Typed</h2> <span>Html.AlertFor(m => m.AlertBoxText).Success()</span> @Html.AlertFor(m => m.AlertBoxText).Success() <span>Html.AlertFor(m => m.AlertBoxText, m => m.AlertBoxStyle)</span> @Html.AlertFor(m => m.AlertBoxText, m => m.AlertBoxStyle)
模型类代码
using System; using System.Collections.Generic; using System.Linq; using System.Web; using MyHelpers; namespace FluentHtmlHelpers.Models { public class SampleAlertModel { public string AlertBoxText { get; set; } public MyHelpers.AlertStyle AlertBoxStyle { get; set; } } }
自定义AlertHtmlHelper代码
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal; namespace MyHelpers { /// <summary> /// Generates an Alert message /// </summary> public static class AlertHtmlHelper { /// <summary> /// Generates an Alert message /// </summary> public static AlertBox Alert(this IHtmlHelper html, string text, AlertStyle alertStyle = AlertStyle.Default, bool hideCloseButton = false, object htmlAttributes = null) { return new AlertBox(text, alertStyle, hideCloseButton, htmlAttributes); } // Strongly typed /// <summary> /// Generates an Alert message /// </summary> public static AlertBox AlertFor<TModel, TTextProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TTextProperty>> expression, AlertStyle alertStyle = AlertStyle.Default, bool hideCloseButton = false, object htmlAttributes = null) { var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider); return new AlertBox((string)metadata.Model, alertStyle, hideCloseButton, htmlAttributes); } /// <summary> /// Generates an Alert message /// </summary> public static AlertBox AlertFor<TModel, TTextProperty, TStyleProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TTextProperty>> textExpression, Expression<Func<TModel, TStyleProperty>> styleExpression, bool hideCloseButton = false, object htmlAttributes = null) { var text = (string) ExpressionMetadataProvider.FromLambdaExpression(textExpression, html.ViewData, html.MetadataProvider).Model; var alertStyle = (AlertStyle)ExpressionMetadataProvider.FromLambdaExpression(styleExpression, html.ViewData, html.MetadataProvider).Model; return new AlertBox(text, alertStyle,hideCloseButton, htmlAttributes); } } }
抛出的错误信息
TypeLoadException: 无法从程序集'Microsoft.AspNetCore.Mvc.ViewFeatures, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60'中加载类型'Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ExpressionMetadataProvider'。
解决方案
原因分析
ASP.NET Core 8.0中,Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.ExpressionMetadataProvider这个内部类型被调整为公开命名空间下的可用类型,不再允许直接引用Internal命名空间内的类型。
修改步骤
- 移除内部命名空间引用:删除代码中
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;这一行。 - 替换元数据获取方式:使用
IHtmlHelper提供的GetModelMetadataFromExpression扩展方法,或者直接调用公开的ExpressionMetadataProvider类方法。
修改后的AlertHtmlHelper代码
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Html; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.ViewFeatures; namespace MyHelpers { /// <summary> /// Generates an Alert message /// </summary> public static class AlertHtmlHelper { /// <summary> /// Generates an Alert message /// </summary> public static AlertBox Alert(this IHtmlHelper html, string text, AlertStyle alertStyle = AlertStyle.Default, bool hideCloseButton = false, object htmlAttributes = null) { return new AlertBox(text, alertStyle, hideCloseButton, htmlAttributes); } // Strongly typed /// <summary> /// Generates an Alert message /// </summary> public static AlertBox AlertFor<TModel, TTextProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TTextProperty>> expression, AlertStyle alertStyle = AlertStyle.Default, bool hideCloseButton = false, object htmlAttributes = null) { // 使用IHtmlHelper扩展方法获取元数据 var metadata = html.GetModelMetadataFromExpression(expression); return new AlertBox((string)metadata.Model, alertStyle, hideCloseButton, htmlAttributes); } /// <summary> /// Generates an Alert message /// </summary> public static AlertBox AlertFor<TModel, TTextProperty, TStyleProperty>(this IHtmlHelper<TModel> html, Expression<Func<TModel, TTextProperty>> textExpression, Expression<Func<TModel, TStyleProperty>> styleExpression, bool hideCloseButton = false, object htmlAttributes = null) { var textMetadata = html.GetModelMetadataFromExpression(textExpression); var styleMetadata = html.GetModelMetadataFromExpression(styleExpression); var text = (string)textMetadata.Model; var alertStyle = (AlertStyle)styleMetadata.Model; return new AlertBox(text, alertStyle, hideCloseButton, htmlAttributes); } } }
补充说明
如果项目中没有GetModelMetadataFromExpression扩展方法,也可以直接调用公开的ExpressionMetadataProvider方法(无需Internal命名空间),调用逻辑和原代码一致:
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, html.ViewData, html.MetadataProvider);
只需确保移除Microsoft.AspNetCore.Mvc.ViewFeatures.Internal的引用即可,当前版本中ExpressionMetadataProvider已在Microsoft.AspNetCore.Mvc.ViewFeatures命名空间下公开可用。
内容的提问来源于stack exchange,提问作者redoc01

