使用AdditionalFields远程验证时,创建商品无法触发Controller问题求助
你遇到的问题核心在于:当给Remote验证添加AdditionalFields="Id"后,ASP.NET MVC的Unobtrusive Remote验证默认会同时监听指定字段(Code和Id)的变化,只有当其中任意一个字段的值改变时才会触发验证请求。
在创建商品场景中,Id是隐藏字段,初始值为0且不会被用户修改,所以当你输入Code时,验证框架认为只有Code变化了,但因为依赖了Id字段且Id没有变化,导致验证请求根本没被触发。而编辑场景下,Id是已有商品的非0值,页面加载时Id值已存在,修改Code时框架会同时发送Code和Id的值,所以验证能正常工作。
这里提供几种实用的解决方法,你可以根据自己的项目场景选择:
方法1:手动配置前端Remote验证规则
绕过框架的默认行为,手动为Code字段添加验证规则,确保每次输入Code时都主动获取Id值并发送请求。
在视图页面的末尾添加以下脚本:
@section Scripts { @Scripts.Render("~/bundles/jqueryval") <script> $(document).ready(function () { // 重新配置Code字段的Remote验证规则 $('#Code').rules('add', { remote: { url: '@Url.Action("IsCodeAvailable", "Product")', type: 'GET', data: { // 每次验证时主动获取Id字段的当前值 Id: function () { return $('#Id').val(); } } }, messages: { remote: 'Product Code already taken' } }); }); </script> }
这样无论Id字段的值是否变化,只要Code内容修改,就会触发验证请求并携带当前Id值。
方法2:修改后端方法参数为可空类型
把后端验证方法的Id参数改为int?(可空整数),这样即使前端没传递Id值也能正常进入方法,再调整判断逻辑:
[HttpGet] public JsonResult IsCodeAvailable(string code, int? Id) { try { var flag = true; // 判断是否为创建操作:Id为null或0 if (!Id.HasValue || Id.Value == 0) { flag = !db.Product.Any(x => x.Code == code); } else { flag = !db.Product.Any(x => x.Code == code && x.Id != Id.Value); } return Json(flag, JsonRequestBehavior.AllowGet); } catch (Exception ex) { return Json(false, JsonRequestBehavior.AllowGet); } }
同时修改模型的Remote属性,去掉AdditionalFields:
[Remote("IsCodeAvailable", "Product", HttpMethod = "GET", ErrorMessage = "Product Code already taken")] public string Code { get; set; }
这种方法让后端自行判断场景,无需依赖前端传递额外字段的变化触发验证。
方法3:拆分ViewModel分离场景
为创建和编辑操作分别定义ViewModel,避免在同一个模型中混合两种场景的验证规则:
创建用ViewModel
public class CreateProductViewModel { [Remote("IsCodeAvailableForCreate", "Product", HttpMethod = "GET", ErrorMessage = "Product Code already taken")] public string Code { get; set; } public string Name { get; set; } }
编辑用ViewModel
public class EditProductViewModel { public int Id { get; set; } [Remote("IsCodeAvailableForEdit", "Product", AdditionalFields = "Id", HttpMethod = "GET", ErrorMessage = "Product Code already taken")] public string Code { get; set; } public string Name { get; set; } }
然后在控制器中实现两个独立的验证方法:
[HttpGet] public JsonResult IsCodeAvailableForCreate(string code) { try { var flag = !db.Product.Any(x => x.Code == code); return Json(flag, JsonRequestBehavior.AllowGet); } catch (Exception ex) { return Json(false, JsonRequestBehavior.AllowGet); } } [HttpGet] public JsonResult IsCodeAvailableForEdit(string code, int Id) { try { var flag = !db.Product.Any(x => x.Code == code && x.Id != Id); return Json(flag, JsonRequestBehavior.AllowGet); } catch (Exception ex) { return Json(false, JsonRequestBehavior.AllowGet); } }
这种方法的优势是职责分离,每个ViewModel只处理对应场景,避免验证规则冲突。
无论选择哪种方法,测试时都可以打开浏览器开发者工具(F12),切换到Network标签页,输入Code后观察是否有向IsCodeAvailable的GET请求发送,以此确认验证是否正常触发。
内容的提问来源于stack exchange,提问作者Iftekhar Rasul

