Asp.net MVC使用FluentValidation返回含超链接的HTML验证消息不渲染?
哪怕你在外层给验证摘要套了Html.Raw也无法渲染HTML标签,核心原因是ASP.NET MVC在生成字段级验证提示、验证摘要内容时,会默认对ModelState中存储的所有验证消息执行HTML编码。你写在FluentValidation规则里的<a>标签,在页面渲染前早就被转成了<a href="test.com">Go Here</a>这种纯文本实体,外层再用Html.Raw也无法逆转已经被编码的内容。
另外你之前写的视图代码存在两个小问题:一是语法缺少右括号,二是ValidationSummary内部生成的错误条目已经完成了编码流程,对整体输出套Html.Raw本质是绕过不了内部的编码逻辑的。
推荐使用局部标记渲染的方式实现带HTML的验证消息,这种方式不需要改动全局安全配置,不会影响其他普通验证消息的编码保护。
步骤1:定义可绕过编码的自定义消息类型
利用ASP.NET MVC内置的IHtmlString接口约定——MVC在渲染输出时,检测到实现了该接口的对象会自动跳过HTML编码流程,直接输出原始内容:
public class HtmlValidationMessage : IHtmlString { private readonly string _rawContent; public HtmlValidationMessage(string rawContent) { _rawContent = rawContent; } public string ToHtmlString() => _rawContent; }
步骤2:在验证流程中手动标记需要渲染HTML的消息
FluentValidation默认集成到MVC时,会把所有验证错误以纯文本形式写入ModelState。你需要在验证逻辑执行后,手动把带HTML的错误消息替换成上面定义的HtmlValidationMessage类型再存入ModelState:
// 举例:执行模型验证 var validator = new YourModelValidator(); var validationResult = validator.Validate(yourInputModel); if (!validationResult.IsValid) { foreach (var error in validationResult.Errors) { // 匹配你定义的带HTML的验证消息,替换为自定义类型 if (error.ErrorMessage == "<a href=\"test.com\">Go Here</a>") { ModelState.AddModelError(error.PropertyName, new HtmlValidationMessage(error.ErrorMessage)); } else { // 普通文本错误沿用默认逻辑存入,保留HTML编码保护 ModelState.AddModelError(error.PropertyName, error.ErrorMessage); } } }
步骤3:视图层正常渲染即可
因为存进ModelState的HTML消息已经标记为IHtmlString类型,你不需要再额外包Html.Raw,不管是验证摘要还是字段级的提示都能正常渲染:
// 验证摘要正常使用,不需要额外转Raw @Html.ValidationSummary(false, "", new {@class ="callout"}) // 单字段的验证提示也会自动正确渲染a标签 @Html.ValidationMessageFor(x => x.Property)
- 绝对不要为了实现该效果直接全局关闭MVC的验证消息HTML编码,这种操作会让所有带用户输入拼接的验证消息失去XSS防护,存在跨站脚本攻击的风险。
- 你写进验证消息的HTML内容,必须是提前定义好的固定内容,绝对不要把用户提交的输入直接拼到验证消息的HTML代码里输出,避免XSS风险。
内容的提问来源于stack exchange,提问作者chobo2

