.NET Core6自定义HTML助手委托签名不兼容问题求助
解决ASP.NET MVC自定义HTML助手迁移至.NET Core 6时的委托签名不兼容问题
错误信息:ArgumentException: Cannot bind to the target method because its signature is not compatible with that of the delegate type
问题根源
- 原代码依赖
.NET Framework中System.Web.Mvc.Html.InputExtensions的私有方法InputHelper、CheckBoxHelper等,但这些方法在.NET Core 6的ASP.NET Core MVC中完全不存在——ASP.NET Core MVC是全新重构的框架,内部实现、类型体系与旧版完全不同。 - 旧版的
HtmlHelper(System.Web.Mvc.HtmlHelper)与Core版的IHtmlHelper(Microsoft.AspNetCore.Mvc.Rendering.IHtmlHelper)是不同类型,方法签名、参数要求差异极大,导致委托无法绑定。 - 旧版的
MvcHtmlString在Core中已替换为HtmlString,但核心问题还是目标方法不存在。
解决方案
彻底移除对旧版私有方法的反射调用,改用ASP.NET Core MVC原生的公开API实现自定义HTML助手,或者直接构建HTML内容。
重构后的代码示例
using System; using System.Collections.Generic; using System.Globalization; using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Html; using RateChangingSystemCore1.MetadataProviders; using RateChangingSystemCore1.Models; using Microsoft.AspNetCore.Mvc.ViewFeatures; using Microsoft.AspNetCore.Mvc.ModelBinding; namespace RateChangingSystemCore1.Extensions { public static class EditorExtensions { private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private static readonly CoopMetadataProvider _metadataProvider = new CoopMetadataProvider(); private static ModelMetadata GetDefinitionMetaData(Definition definition) { if (HttpContextHelper.Current.Items.TryGetValue("definitionMetaDataCache", out var cacheObj) && cacheObj is Dictionary<int, ModelMetadata> definitionMetaDataCache) { if (definitionMetaDataCache.TryGetValue(definition.NodeID, out var metadata)) { return metadata; } } else { var definitionMetaDataCache = new Dictionary<int, ModelMetadata>(); HttpContextHelper.Current.Items["definitionMetaDataCache"] = definitionMetaDataCache; } log.DebugFormat("Making meta data for {0}", definition.NodeID); // 注意:Core中ModelMetadata的创建方式需调整,确保CoopMetadataProvider适配Core的IModelMetadataProvider接口 var modelMetadata = _metadataProvider.CreateMetadata2(null, typeof(Definition), () => definition, typeof(Definition), null); ((Dictionary<int, ModelMetadata>)HttpContextHelper.Current.Items["definitionMetaDataCache"])[definition.NodeID] = modelMetadata; return modelMetadata; } private static HtmlString CoopEditorCommon(this IHtmlHelper html, string name, object value, IDictionary<string, object> htmlAttributes, Definition definition, Func<ModelMetadata, object, HtmlString> inputHelper) { definition = definition ?? html.ViewData["Definition"] as Definition; var modelMetadata = GetDefinitionMetaData(definition); object formattedModelValue = definition.ValueValue; string formatString = modelMetadata.EditFormatString; if (modelMetadata.ModelType != null && !string.IsNullOrEmpty(formatString)) { formattedModelValue = string.Format(CultureInfo.CurrentCulture, formatString, definition.ValueValue); } return inputHelper(modelMetadata, formattedModelValue); } public static HtmlString CoopTextBox(this IHtmlHelper html, string name, object value, IDictionary<string, object> htmlAttributes) { return CoopEditorCommon(html, name, value, htmlAttributes, null, (modelMetadata, formattedModelValue) => { // 改用Core原生的TextBox方法,或直接构建input元素 return html.TextBox(name, formattedModelValue, htmlAttributes); }); } public static HtmlString CoopTextBox(this IHtmlHelper html, string name, object value, Definition definition, IDictionary<string, object> htmlAttributes) { return CoopEditorCommon(html, name, value, htmlAttributes, definition, (modelMetadata, formattedModelValue) => { return html.TextBox(name, formattedModelValue, htmlAttributes); }); } public static HtmlString CoopCheckBoxFor(this IHtmlHelper html, string name, object value, IDictionary<string, object> htmlAttributes) { return CoopEditorCommon(html, name, value, htmlAttributes, null, (modelMetadata, formattedModelValue) => { bool isChecked = formattedModelValue != null && bool.TryParse(formattedModelValue.ToString(), out var result) && result; return html.CheckBox(name, isChecked, htmlAttributes); }); } public static HtmlString CoopCheckBoxFor(this IHtmlHelper html, string name, object value, Definition definition, IDictionary<string, object> htmlAttributes) { return CoopEditorCommon(html, name, value, htmlAttributes, definition, (modelMetadata, formattedModelValue) => { bool isChecked = formattedModelValue != null && bool.TryParse(formattedModelValue.ToString(), out var result) && result; return html.CheckBox(name, isChecked, htmlAttributes); }); } public static HtmlString CoopMultiLineBox(this IHtmlHelper html, string name, object value, IDictionary<string, object> htmlAttributes) { return CoopEditorCommon(html, name, value, htmlAttributes, null, (modelMetadata, formattedModelValue) => { return html.TextArea(name, formattedModelValue?.ToString(), htmlAttributes); }); } public static HtmlString CoopMultiLineBox(this IHtmlHelper html, string name, object value, Definition definition, IDictionary<string, object> htmlAttributes) { return CoopEditorCommon(html, name, value, htmlAttributes, definition, (modelMetadata, formattedModelValue) => { return html.TextArea(name, formattedModelValue?.ToString(), htmlAttributes); }); } } }
额外注意事项
- 确保
CoopMetadataProvider适配ASP.NET Core的IModelMetadataProvider接口,旧版的CreateMetadata方法签名在Core中已变更,需调整实现。 - 移除所有对
System.Web.Mvc命名空间的引用,替换为Microsoft.AspNetCore.Mvc相关命名空间。 HttpContextHelper在Core中需基于IHttpContextAccessor实现,确保能正确获取当前HttpContext。
内容的提问来源于stack exchange,提问作者pooja sankpal
相关产品推荐
相关产品推荐

