簡體   English   中英

如何將復雜類綁定到視圖,同時保留我的自定義驗證屬性?

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

在我的項目中,我有一個使用另一個類的模型類,如下面的示例所示。 模型中的一個屬性取決於對子對象屬性的驗證 - 在此示例中,LastName屬性依賴於對Address.PostalCode屬性值的驗證。 我實現了一個自定義驗證屬性來驗證我的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 = "";
}

問題是在控制器中,Address屬性不是從視圖構造的,並且它始終為null。 在此示例中,無論我在視圖中發送什么,user.Address始終為null。 這是控制器代碼。

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

這是觀點:

        <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>

為了解決這個問題,我創建了一個自定義虛擬綁定器,將視圖中的字段映射到模型中的屬性,如下所示:

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;
    }

綁定器工作正常,但驗證屬性不再起作用。 我認為必須有一個更好的方法來進行綁定比這個,是嗎?

這個綁定器只是將LastName映射到LastName,將Address.streetName映射到Address.streetName,我想應該有一種方法可以實現這一點,而不必編寫所有這些繁瑣的代碼而不破壞自定義驗證機制。

您需要使用屬性而不是公共字段才能使默認模型綁定正常工作。

將您的AddressType類更改為:

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

一種解決方案是在我的子類中使用屬​​性而不是公共字段 - 感謝Oded的答案!

另一個解決方案是在控制器中調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM