【问题标题】:Custom Model Binder Not Validating Model自定义模型绑定器不验证模型
【发布时间】:2012-01-29 22:20:40
【问题描述】:

我开始使用 knockout.js,并在此过程中使用了 FromJsonAttribute(由 Steve Sanderson 创建)。我遇到了自定义属性未执行模型验证的问题。我整理了一个简单的例子——我知道它看起来像很多代码——但基本问题是如何在自定义模型绑定器中强制验证模型。

using System.ComponentModel.DataAnnotations;

namespace BindingExamples.Models
{
    public class Widget
    {
        [Required]
        public string Name { get; set; }
    }
}

这是我的控制器:

using System;
using System.Web.Mvc;
using BindingExamples.Models;

namespace BindingExamples.Controllers
{
    public class WidgetController : Controller
    {

        public ActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public ActionResult Index(Widget w)
        {
            if(this.ModelState.IsValid)
            {
                TempData["message"] = String.Format("Thanks for inserting {0}", w.Name);
                return RedirectToAction("Confirmation");
            }
            return View(w);
        }

        [HttpPost]
        public ActionResult PostJson([koListEditor.FromJson] Widget w)
        {
            //the ModelState.IsValid even though the widget has an empty Name
            if (this.ModelState.IsValid)
            {
                TempData["message"] = String.Format("Thanks for inserting {0}", w.Name);
                return RedirectToAction("Confirmation");
            }
            return View(w);
        }

        public ActionResult Confirmation()
        {
            return View();
        }

    }
}

我的问题是模型在我的 PostJson 方法中始终有效。为了完整起见,这里是 FromJson 属性的 Sanderson 代码:

using System.Web.Mvc;
using System.Web.Script.Serialization;

namespace koListEditor
{
    public class FromJsonAttribute : CustomModelBinderAttribute
    {
        private readonly static JavaScriptSerializer serializer = new JavaScriptSerializer();

        public override IModelBinder GetBinder()
        {
            return new JsonModelBinder();
        }

        private class JsonModelBinder : IModelBinder
        {
            public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
            {
                var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
                if (string.IsNullOrEmpty(stringified))
                    return null;
                var model = serializer.Deserialize(stringified, bindingContext.ModelType);
                return model;
            }
        }
    }
}

【问题讨论】:

  • 请查看我的回答。祝你有美好的一天。

标签: asp.net-mvc json data-annotations custom-model-binder


【解决方案1】:

首先,我才刚刚开始学习 ASP.NET,所以不要认真对待我的解决方案。我找到了this article,就像你一样,尝试做一个自定义模型活页夹。没有验证。然后我只是用 DefaultModelBinder 和 voula 替换了 IModelBinder 接口,它可以工作。希望我能帮助别人

【讨论】:

    【解决方案2】:

    谢谢,谢谢,dknaack!你的答案正是我想要的,除了我想在每个属性绑定后验证 b/c 我有依赖于其他属性的属性,如果依赖属性无效,我不想继续绑定。

    这是我的新 BindProperty 重载:

    protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor){
    
        // if this is a simple property, bind it and return
        if(_simplePropertyKeys.ContainsKey(propertyDescriptor.Name)){
            this.BindSimpleProperty(bindingContext, propertyDescriptor);
    
        // if this is complex property, only bind it if we don't have an error already
        } else if (bindingContext.ModelState.IsValid){
            this.BindComplexProperty(bindingContext, propertyDescriptor);
        }
    
        // add errors from the data annotations
        propertyDescriptor.Attributes.OfType<ValidationAttribute>()
            .Where(a => a.IsValid(propertyDescriptor.GetValue(bindingContext.Model)) == false)
            .ForEach(r => bindingContext.ModelState.AddModelError(propertyDescriptor.Name, r.ErrorMessage));
    }
    

    【讨论】:

      【解决方案3】:

      说明

      FromJsonAttribute 仅绑定到模型,并且如您所说,没有验证。

      您可以向FromJsonAttribute 添加验证,以根据他的 DataAnnotations 属性验证模型。

      这可以使用TypeDescriptor 类来完成。

      TypeDescriptor 提供有关组件特征的信息,例如其属性、属性和事件。

      查看我的解决方案。我已经测试过了。

      解决方案

      private class JsonModelBinder : IModelBinder
      {
          public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
          {
              var stringified = controllerContext.HttpContext.Request[bindingContext.ModelName];
              if (string.IsNullOrEmpty(stringified))
                  return null;
              var model = serializer.Deserialize(stringified, bindingContext.ModelType);
      
              // DataAnnotation Validation
              var validationResult = from prop in TypeDescriptor.GetProperties(model).Cast<PropertyDescriptor>()
                                      from attribute in prop.Attributes.OfType<ValidationAttribute>()
                                      where !attribute.IsValid(prop.GetValue(model))
                                      select new { Propertie = prop.Name, ErrorMessage = attribute.FormatErrorMessage(string.Empty) };
      
              // Add the ValidationResult's to the ModelState
              foreach (var validationResultItem in validationResult)
                  bindingContext.ModelState.AddModelError(validationResultItem.Propertie, validationResultItem.ErrorMessage);
      
              return model;
          }
      }
      

      更多信息

      【讨论】:

      • 很高兴为您提供帮助!祝你有美好的一天!
      猜你喜欢
      • 1970-01-01
      • 2012-11-20
      • 1970-01-01
      • 2019-11-16
      • 1970-01-01
      • 1970-01-01
      • 2015-08-30
      • 1970-01-01
      • 2017-04-19
      相关资源
      最近更新 更多