12

私は複雑なモデルを持っています。

いくつかのプロパティを持つ myUserViewModelがあり、そのうちの 2 つはHomePhoneandWorkPhoneです。タイプの両方PhoneViewModelPhoneViewModel私は、CountryCodeおよびAreaCodeすべてNumberの文字列を持っています。CountryCodeオプションでAreaCodeありながら必須にしたいNumber

これはうまくいきます。私の問題は、UserViewModel WorkPhoneが必須であり、HomePhoneそうでないことです。

プロパティに属性を設定してRequire属性を無効にできる方法はありますか?PhoneViewModelHomeWork

私はこれを試しました:

[ValidateInput(false)]

ただし、それはクラスとメソッドのみです。

コード:

public class UserViewModel
{
    [Required]
    public string Name { get; set; }

    public PhoneViewModel HomePhone { get; set; }

    [Required]    
    public PhoneViewModel WorkPhone { get; set; }
}

public class PhoneViewModel
{
    public string CountryCode { get; set; }

    public string AreaCode { get; set; }

    [Required]
    public string Number { get; set; }
}
4

4 に答える 4

5

[アイデアをより明確にするために2012年5月24日に更新]

これが正しいアプローチかどうかはわかりませんが、概念を拡張して、より一般的で再利用可能なアプローチを作成できると思います。

ASP.NET MVCでは、検証はバインド段階で行われます。サーバーにフォームを投稿するDefaultModelBinder場合、はリクエスト情報からモデルインスタンスを作成し、検証エラーをに追加するものModelStateDictionaryです。

あなたの場合、バインディングが検証で発生する限りHomePhone、検証が起動し、カスタム検証属性または同様の種類を作成することによってこれについて多くを行うことはできないと思います

フォームに使用可能な値(エリアコード、国コード、数値または空)HomePhoneがない場合、プロパティのモデルインスタンスをまったく作成しないと考えています。バインディングを制御する場合、検証を制御します。カスタムモデルバインダーを作成します。

カスタムモデルバインダーでは、プロパティがHomePhoneであるかどうか、フォームにそのプロパティの値が含まれているかどうかを確認しています。含まれていない場合は、プロパティをバインドせず、の検証は行われませんHomePhone。単純に、の値は。HomePhoneでnullになりますUserViewModel

  public class CustomModelBinder : DefaultModelBinder
  {
      protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
      {
        if (propertyDescriptor.Name == "HomePhone")
        {
          var form = controllerContext.HttpContext.Request.Form;

          var countryCode = form["HomePhone.CountryCode"];
          var areaCode = form["HomePhone.AreaCode"];
          var number = form["HomePhone.Number"];

          if (string.IsNullOrEmpty(countryCode) && string.IsNullOrEmpty(areaCode) && string.IsNullOrEmpty(number))
            return;
        }

        base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
      }
  }

最後に、カスタムモデルバインダーをglobal.asax.csに登録する必要があります。

  ModelBinders.Binders.Add(typeof(UserViewModel), new CustomModelBinder());

これで、UserViewModelをパラメーターとして受け取るアクションができました。

 [HttpPost]
 public Action Post(UserViewModel userViewModel)
 {

 }

カスタムモデルバインダーが機能し、フォームのエリアコード、国コード、および番号の値は投稿されません。HomePhone検証エラーは発生せず、userViewModel.HomePhoneはnullです。フォームがこれらのプロパティの値のいずれかを少なくとも投稿する場合、検証はHomePhone期待どおりに行われます。

于 2012-05-23T17:28:01.473 に答える
2

私は modelBinder を使用しません。カスタム ValidationAttribute を使用します。

public class UserViewModel
{
    [Required]
    public string Name { get; set; }

    public HomePhoneViewModel HomePhone { get; set; }

    public WorkPhoneViewModel WorkPhone { get; set; }
}

public class HomePhoneViewModel : PhoneViewModel 
{
}

public class WorkPhoneViewModel : PhoneViewModel 
{
}

public class PhoneViewModel 
{
    public string CountryCode { get; set; }

    public string AreaCode { get; set; }

    [CustomRequiredPhone]
    public string Number { get; set; }
}

その後:

[AttributeUsage(AttributeTargets.Property]
public class CustomRequiredPhone : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ValidationResult validationResult = null;

        // Check if Model is WorkphoneViewModel, if so, activate validation
        if (validationContext.ObjectInstance.GetType() == typeof(WorkPhoneViewModel)
         && string.IsNullOrWhiteSpace((string)value) == true)
        {
            this.ErrorMessage = "Phone is required";
            validationResult = new ValidationResult(this.ErrorMessage);
        }
        else
        {
            validationResult = ValidationResult.Success;
        }

        return validationResult;
    }
}

明確でない場合は、説明を提供しますが、それはかなり自明だと思います。

于 2012-05-24T09:17:52.763 に答える
1

いくつかの観察: 次のコードは、バインディングが単純なフィールド以上のものである場合に問題を引き起こします。オブジェクトにネストされたオブジェクトがあり、それをスキップして、ネストされたオブジェクトにバインドされていないファイルがある場合があります。

可能な解決策は

protected override void BindProperty(ControllerContext controllerContext, ModelBindingContext bindingContext, PropertyDescriptor propertyDescriptor)
     {
         if (!propertyDescriptor.Attributes.OfType<RequiredAttribute>().Any())
         {
             var form = controllerContext.HttpContext.Request.Form;

             if (form.AllKeys.Where(k => k.StartsWith(string.Format(propertyDescriptor.Name, "."))).Count() > 0)
             {
                 if (form.AllKeys.Where(k => k.StartsWith(string.Format(propertyDescriptor.Name, "."))).All(
                         k => string.IsNullOrWhiteSpace(form[k])))
                     return;
             }
         }

         base.BindProperty(controllerContext, bindingContext, propertyDescriptor);
     }

アルタフ・カトリに感謝

于 2013-08-26T20:13:31.797 に答える