【问题标题】:How to prevent validation of relationships in model binder?如何防止验证模型绑定器中的关系?
【发布时间】:2010-07-16 11:14:57
【问题描述】:

举个例子,如果我有一个名为 Order 的类,其中有一个引用客户的字段,然后是一个带有下拉列表 ( e.Customer.ID, new SelectList( ...)) %>) 用于设置客户,模型绑定器将创建一个仅设置 ID 的空客户。这适用于 NHibernate,但是当将验证添加到 Customer 类的某些字段时,模型绑定器会说这些字段是必需的。如何防止模型绑定器验证这些引用?

谢谢!

【问题讨论】:

    标签: asp.net-mvc-2 modelbinders


    【解决方案1】:

    古老的问题,但我想我还是会为后代回答。在这种情况下,您需要一个自定义模型绑定器来拦截该属性,然后再尝试绑定它。默认模型绑定器将递归尝试使用其自定义绑定器绑定属性,如果未设置,则使用默认绑定器。

    您在 DefaultModelBinder 中寻找的覆盖是 GetPropertyValue。这会在模型中的所有属性上调用,默认情况下它会回调 DefaultModelBinder.BindModel - 整个过程的入口点。

    简化模型:

    public class Organization
    {
        public int Id { get; set; }
    
        [Required]
        public OrganizationType Type { get; set; }
    }
    
    public class OrganizationType
    {
        public int Id { get; set; }
    
        [Required, MaxLength(30)]
        public string Name { get; set; }
    }
    

    查看:

    <div class="editor-label">
        @Html.ErrorLabelFor(m => m.Organization.Type)
    </div>
    <div class="editor-field">
         @Html.DropDownListFor(m => m.Organization.Type.Id, Model.OrganizationTypes, "-- Type")
    </div>
    

    模型绑定器:

    public class OrganizationModelBinder : DefaultModelBinder
    {
        protected override object GetPropertyValue(
            ControllerContext controllerContext, 
            ModelBindingContext bindingContext, 
            System.ComponentModel.PropertyDescriptor propertyDescriptor, 
            IModelBinder propertyBinder)
        {
            if (propertyDescriptor.PropertyType == typeof(OrganizationType))
            {
                var idResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".Id");
                if (idResult == null || string.IsNullOrEmpty(idResult.AttemptedValue))
                {
                    return null;   
                }
    
                var id = (int)idResult.ConvertTo(typeof(int));
                // Can validate the id against your database at this point if needed...
                // Here we just create a stub object, skipping the model binding and
                // validation on OrganizationType
                return new OrganizationType { Id = id };
            }
    
            return base.GetPropertyValue(controllerContext, bindingContext, propertyDescriptor, propertyBinder);
        }
    }
    

    请注意,在视图中,我们为 model.foo.bar.Id 创建了 DropDownList。在模型绑定器中,确保也将其添加到模型名称中。您可以不使用两者,但是 DropDownListFor 在查找所选值时会遇到一些问题,而无需在您发送的 SelectList 中预先选择它。

    最后,回到控制器,确保在你的数据库上下文中附加这个属性(如果你使用的是实体框架,其他人可能会以不同的方式处理)。否则,它不会被跟踪,并且上下文将尝试在保存时添加它。

    控制器:

    public ActionResult Create(Organization organization)
    {
        if (ModelState.IsValid)
        {
            _context.OrganizationTypes.Attach(organization.Type);
            _context.Organizations.Add(organization);
            _context.SaveChanges();
    
            return RedirectToAction("Index");
        }
    
        // Build up view model...
        return View(viewModel);
    }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多