关于Asp.Net MVC 中 UpdateModel 的未能更新***模型的 解决方案!

最近遇到一个很古怪的问题,以前倒是没有发现!!!记录下

测试中预设的故障环境

模型,模型两个都是必须的不能为null

    public class TestModel
    {
        //#region 基元
        [Key]
        public Guid id { get; set; }

        [Required]
        public string Keywords { get; set; }

        [Required]
        public string Title { get; set; }
    }
执行方法
        public ActionResult test(TestModel im)
        {
            try
            {
                var s = new TestModel { id = Guid.Empty, Title = "1", Keywords = "2" };

                UpdateModel<TestModel>(s);

                return Json(new { success = true, s, ModelState.IsValid }, "text/html", JsonRequestBehavior.AllowGet);
            }
            catch (InvalidOperationException ex)
            {
                return Json(new { success = false, error = ex.Message }, "text/html", JsonRequestBehavior.AllowGet);
            }
        }

请求数据 故意丢失一个模型的值 keyword

http://localhost:3981/Article/test?id=00000000-0000-0000-0000-000000000201&islock=true&Title=1

得到结果

{"success":false,"error":"未能更新类型“Model.TestModel”的模型。"}

但是我的 方法内是有 keyword 值的..为什么会更新错误,为什么会出现这个问题? 抛出错误的是 UpdateModel<TestModel>(s), 抛出 InvalidOperationException 异常.

中间还有很多猜想写在这里就不去验证了:

1.猜想先验证 TestModel 如果不符合模型要求就抛出错误.

    结论,如同使用上面的方法 是验证TestModel,但是不是在UpdateModel 中验证.

2.猜想UpdateModel 数据以后再验证是否符合模型,如果不符合就抛出错误.

   结论,不是这样的逻辑

3.更换Action参数.为Guid Id

   结论,运行正常了,那里除了问题? 查找源代码结论和验证就写在下面了

Action 修正参数,可以正常保存

        public ActionResult test(Guid id)
        {
            try
            {
                var s = new TestModel { id = Guid.Empty, Title = "1", Keywords = "2" };

                UpdateModel<TestModel>(s);

                return Json(new { success = true, s, ModelState.IsValid }, "text/html", JsonRequestBehavior.AllowGet);
            }
            catch (InvalidOperationException ex)
            {
                return Json(new { success = false, error = ex.Message }, "text/html", JsonRequestBehavior.AllowGet);
            }
        }

请求数据

http://localhost:3981/Article/test?id=00000000-0000-0000-0000-000000000201&islock=true&Title=1

得到结果

{"success":true,"s":{"id":"00000000-0000-0000-0000-000000000201","Keywords":"2","Title":"1"},"IsValid":true}

一切正常了,why???


直接检查MVC源代码: 真是的很坑爹的结果:


UpdateModel最终都要执行下面这两个方法

        protected internal void UpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class {
            bool success = TryUpdateModel(model, prefix, includeProperties, excludeProperties, valueProvider);
            if (!success) {
                string message = String.Format(CultureInfo.CurrentCulture, MvcResources.Controller_UpdateModel_UpdateUnsuccessful,
                    typeof(TModel).FullName);
                throw new InvalidOperationException(message);
            }
        }

        protected internal bool TryUpdateModel<TModel>(TModel model, string prefix, string[] includeProperties, string[] excludeProperties, IValueProvider valueProvider) where TModel : class {
            if (model == null) {
                throw new ArgumentNullException("model");
            }
            if (valueProvider == null) {
                throw new ArgumentNullException("valueProvider");
            }

            Predicate<string> propertyFilter = propertyName => BindAttribute.IsPropertyAllowed(propertyName, includeProperties, excludeProperties);
            IModelBinder binder = Binders.GetBinder(typeof(TModel));

            ModelBindingContext bindingContext = new ModelBindingContext() {
                ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(TModel)),
                ModelName = prefix,
                ModelState = ModelState,
                PropertyFilter = propertyFilter,
                ValueProvider = valueProvider
            };
            binder.BindModel(ControllerContext, bindingContext);
            return ModelState.IsValid;
        }

请注意最后一句,是什么?  是不是检查当前Action 中参数的 ModelState.IsValid,这个就是原因所在了,当我从 TestModel  转换到 id 的时候 ModelState.IsValid 从假变成了真

所以不会抛出了错误 InvalidOperationException


结论:要使用UpdateModel 方法必须保证Action中所有参数的模型都必须符合模型要求.即 ModelState.IsValid 必须为真


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值