Umbraco 11表单POST提交异常问题及解决方案咨询
1. 异常原因及解决方法
原因
你的ExampleViewModel继承了PublishedContentWrapped,这个类的核心是包装Umbraco的PublishedContent节点数据,必须依赖完整的Umbraco发布模型(比如自动生成的Example节点类型)才能实例化。但表单POST时,前端仅提交了自定义文本框的字段值,没有携带Umbraco节点的上下文数据,模型绑定器无法将提交的简单表单数据(匹配自动生成的Example模型)转换成你的ExampleViewModel,因此抛出ModelBindingException。另外,RenderController的设计初衷是处理页面GET渲染请求,依赖Umbraco内容节点上下文,并不适合处理表单POST场景。
解决方法
如果坚持用RenderController处理POST,需要在表单中携带节点标识并手动构建ViewModel:
- 在表单中添加隐藏字段传递当前节点ID:
<input type="hidden" name="id" value="@Model.Id" /> - 在控制器POST方法中,先通过节点ID获取PublishedContent,再构建ViewModel:
[HttpPost] public IActionResult Index(int id, ExampleViewModel model) { var content = Umbraco.Content(id); if (content == null) return NotFound(); // 用节点重新构建ViewModel,再赋值表单提交的字段 var viewModel = new ExampleViewModel(content); viewModel.CustomField = model.CustomField; if (!ModelState.IsValid) { return CurrentTemplate(viewModel); } return RedirectToAction("Success"); }
但更推荐改用SurfaceController,它专门用于Umbraco的表单交互,不需要依赖页面PublishedContent上下文,适配性更强。
2. SurfaceController 处理表单并带回验证错误
第一步:创建纯表单模型和SurfaceController
不要让表单模型继承PublishedContentWrapped,单独定义纯表单模型:
public class ExampleFormModel { public string CustomField { get; set; } }
编写SurfaceController处理表单提交:
public class ExampleSurfaceController : SurfaceController { [HttpPost] public IActionResult SubmitForm(ExampleFormModel model) { // 自定义验证逻辑 if (string.IsNullOrWhiteSpace(model.CustomField)) { ModelState.AddModelError(nameof(model.CustomField), "此字段不能为空"); } if (!ModelState.IsValid) { // 验证失败返回当前页面,错误自动存入TempData return CurrentUmbracoPage(); } // 验证通过跳转目标页面,替换为你的目标节点ID return RedirectToUmbracoPage(1234); } }
第二步:视图中渲染表单并显示错误
使用Html.BeginUmbracoForm生成表单,用ValidationMessageFor显示字段错误:
@using (Html.BeginUmbracoForm<ExampleSurfaceController>("SubmitForm")) { @Html.LabelFor(m => m.CustomField) @Html.TextBoxFor(m => m.CustomField) @Html.ValidationMessageFor(m => m.CustomField) <button type="submit">提交</button> }
CurrentUmbracoPage()会自动将ModelState错误存入TempData,回到页面后Html.ValidationMessageFor可直接读取显示。如需全局错误提示,添加:
@Html.ValidationSummary()
内容的提问来源于stack exchange,提问作者5NRF

