简体   繁体   English

如何将复杂类绑定到视图,同时保留我的自定义验证属性?

[英]how can I bind a complex class to a view, while preserving my custom validation attributes?

In my project I have a model class that uses another class, like in the sample below. 在我的项目中,我有一个使用另一个类的模型类,如下面的示例所示。 One of the properties in the model depends for validation on on of the properties of a child object -- in this sample, LastName property depends for validation on the value of the Address.PostalCode property. 模型中的一个属性取决于对子对象属性的验证 - 在此示例中,LastName属性依赖于对Address.PostalCode属性值的验证。 I implemented a custom validation attribute to validate my LastName property and it works great. 我实现了一个自定义验证属性来验证我的LastName属性,它运行良好。

public class User
{
    public static ValidationResult ValidateLastName(string lastName, ValidationContext context)
    {
        // Grab the model instance
        var user = context.ObjectInstance as User;
        if (user == null)
            throw new NullReferenceException();

        // Cross-property validation
        if (user.Address.postalCode.Length < 10000)
            return new ValidationResult("my LastName custom validation message.");

        return ValidationResult.Success;
    }

    [Display(Name = "Last name")]
    [CustomValidationAttribute(typeof(User), "ValidateLastName")]
    public string LastName { get; set; }

    [Display(Name = "First name")]
    public string FirstName { get; set; }

    [Display(Name = "Address:")]
    [CustomValidationAttribute(typeof(User), "ValidateAddress")]
    public AddressType Address { get; set; }
}

public class AddressType
{
    public string streetName = "";

    public string streetNumber = "";
    public string postalCode = "";
}

The problem is in the controller the Address property does not get constructed from the view, and it is always null. 问题是在控制器中,Address属性不是从视图构造的,并且它始终为null。 In this sample, user.Address is always null, regardless of what I send in the view. 在此示例中,无论我在视图中发送什么,user.Address始终为null。 Here is the controller code. 这是控制器代码。

    [HttpPost]
    public ActionResult Create(User user)
    {
        if (ModelState.IsValid)
        {
            // creation code here
            return RedirectToAction("Index");
        }
        else
        {
            return View(user);
        }
    }

Here is the view: 这是观点:

        <div class="editor-label">
            @Html.LabelFor(model => model.Address.postalCode)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Address.postalCode)
            @Html.ValidationMessageFor(model => model.Address.postalCode)
        </div>

To resolve this, I created a custom dummy binder to map the fields in the view to the properties in the model like so: 为了解决这个问题,我创建了一个自定义虚拟绑定器,将视图中的字段映射到模型中的属性,如下所示:

public class UserBinder : IModelBinder
{
    private string GetValue(ModelBindingContext bindingContext, string key)
    {
        var result = bindingContext.ValueProvider.GetValue(key);
        return (result == null) ? null : result.AttemptedValue;
    }

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        User instance = new User();
        instance.FirstName = GetValue(bindingContext, "FirstName"); //controllerContext.HttpContext.Request["FirstName"];
        instance.LastName = GetValue(bindingContext, "LastName"); //controllerContext.HttpContext.Request["LastName"];

        instance.Address = new AddressType();
        string streetName = controllerContext.HttpContext.Request["Address.streetName"];

        //ModelStateDictionary mState = bindingContext.ModelState;
        //mState.Add("LastName", new ModelState { });
        //mState.AddModelError("LastName", "There's an error.");

        instance.Address.streetName = streetName;
                    ...
        return instance;
    }

The binder works fine, but the validation attributes do not work anymore. 绑定器工作正常,但验证属性不再起作用。 I think there must be a better way to do the binding than this, is there? 我认为必须有一个更好的方法来进行绑定比这个,是吗?

This binder is just mapping LastName to LastName and Address.streetName to Address.streetName, I imagine there should be a way to accomplish this without having to write all this tedious code and without breaking the custom validation mechanism. 这个绑定器只是将LastName映射到LastName,将Address.streetName映射到Address.streetName,我想应该有一种方法可以实现这一点,而不必编写所有这些繁琐的代码而不破坏自定义验证机制。

You need to use properties instead of public fields in order for the default model binding to work properly. 您需要使用属性而不是公共字段才能使默认模型绑定正常工作。

Change your AddressType class to: 将您的AddressType类更改为:

public class AddressType
{
    public string streetName { get; set; }
    public string streetNumber { get; set; }
    public string postalCode { get; set; }
}

One solution is to use properties instead of public fields in my child class -- thanks to Oded for the answer! 一种解决方案是在我的子类中使用属​​性而不是公共字段 - 感谢Oded的答案!

Another solution is to call TryValidateModel in the controller, this enables my validation code even with the binder present. 另一个解决方案是在控制器中调用TryValidateModel,即使存在绑定器,也可以启用我的验证代码。

    [HttpPost]
    public ActionResult Create(User user)
    {
        if (TryValidateModel(user))
        {
            // creation code here
            return RedirectToAction("Index");
        }
        else
        {
            return View(user);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何绑定具有复杂对象属性的对象集合? - How can I bind my collection of objects with complex object attribute? 如何在我的视图中访问模型中的属性 - How can I access the attributes from my model in my view 在Umbraco中,如何将对象的通用列表绑定到我的视图? - In Umbraco, how can I bind a generic list of Objects to my View? 将自定义类与 WPF 中的验证绑定 - Bind custom class with Validation in WPF 如何使用XAML中的另一个自定义控件基类使WPF在视图中实例化一个自定义控件? - How can I make WPF instantiate a custom control in my view, using another custom control base class in my XAML? 自定义标签助手:如何在属性中使用复杂对象? - Custom tag helper: How do I use complex objects in attributes? 如何对自定义验证属性进行单元测试 - How can I unit test my custom validation attribute XAML data.binding-如何将方法中的属性绑定到视图中的经度/纬度? - XAML data.binding - how can I bind properties in my method to the longitude/latitude in my view? Xamarin和MVVM-如何将View中的Boxview绑定到ViewModel中的Color数组? - Xamarin and MVVM - How can I bind a Boxview in my View to an array of Color in my ViewModel? 如何将我的自定义用户控件及其自定义视图 model 包含到我的 xaml 视图中? - How can I include my custom user control with its custom view model into my xaml view?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM