tickwave
tickwave

Reputation: 3455

Check "ModelState.IsValid" only on certain part of the Model

I'm using ASP.NET-MVC Core 2.1 and I have this ViewModel class in my code

    public class HomeViewModel
    {
        public HomeViewModel()
        {
            Section1 = new HomeSection1ViewModel();
            Section2 = new HomeSection2ViewModel();
        }

        public HomeSection1ViewModel Section1 { get; set; }
        public HomeSection2ViewModel Section2 { get; set; }
    }

    public class HomeSection1ViewModel
    {
        public Guid ID { get; set; }
        [Required(ErrorMessage = "Required")]
        public string Title { get; set; }
        [Required(ErrorMessage = "Required")]
        public string Description { get; set; }
        [Required(ErrorMessage = "Required")]
        public string Link { get; set; }
    }

    public class HomeSection2ViewModel
    {
        public HomeSection2ViewModel()
        {
            Details = new List<HomeSection2DetailViewModel>();
        }

        public Guid ID { get; set; }
        [Required(ErrorMessage = "Required")]
        public string Title { get; set; }
        [Required(ErrorMessage = "Required")]
        public string Header { get; set; }
        public List<HomeSection2DetailViewModel> Details { get; set; }
    }

    public class HomeSection2DetailViewModel
    {
        public Guid ID { get; set; }
        [Required(ErrorMessage = "Required")]
        public string Title { get; set; }
        public string Description { get; set; }
        public string Link { get; set; }
        [Required(ErrorMessage = "Required")]
        [Range(0, int.MaxValue, ErrorMessage = "Please enter a valid number")]
        public int? Sequence { get; set; }
        public DatabaseAction Action { get; set; }
    }  

My view page will bind HomeViewModel as its Model, my question is how do I validate only certain part of the Model? For example I want to validate Section2 but not Section1 in my Controller. How do I achieve that?

Any response will be appreciated.

Upvotes: 3

Views: 2749

Answers (3)

user3559349
user3559349

Reputation:

Your HomeViewModel has a constructor which initializes both the HomeSection1ViewModel and HomeSection2ViewModel properties. The DefaultModelBinder initializes an instance of HomeViewModel in the POST method and calls its constructor which means that both Section1 and Section2 properties are initialized, but because you are only posing values for only one, the other will be invalid because of the validation attributes applied to its properties.

Remove the constructor from HomeViewModel so that only Section2 is initialized by the DefaultModelBinder (based on values from the request). Section1 will be null by default, therefore no validation is performed on any of its properties.

Upvotes: 1

Steve Tolba
Steve Tolba

Reputation: 1487

Looks like you will be binding your HomeViewModel to different Views and in some Views you want to validate some properties as mentioned.

There are multiple approaches to get this done, here are 2 I can think of:

1- Implement IValidatableObject in your ViewModel

public class HomeSection2ViewModel : : IValidatableObject
{
    public HomeSection2ViewModel()
    {
        Details = new List<HomeSection2DetailViewModel>();
    }

    public Guid ID { get; set; }

    public string Title { get; set; }

    public string Header { get; set; }
    public bool Validate { get; set; }
    public List<HomeSection2DetailViewModel> Details { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
      if(Validate)
      {
          if(string.IsNullOrEmpty(Title)
          {
               yield return
                    new ValidationResult(errorMessage: "required",
                        memberNames: new[] { "Title" });
          }
      }
    }
}

2- Or Bind each View to a version of the ViewModel with the required validation and use AutoMapper to map the Model to the ViewModel or the ViewModel to another ViewModel.

Upvotes: 0

Ctrl-Z
Ctrl-Z

Reputation: 11

This could be achieved by client-side authentication and not server-side.
Else you could override your model.

public class BaseModel
{
   [Required]
   public string RequiredProperty { get; set; }
}


public class DerivativeModel : BaseModel
{
    new public string RequiredProperty { get; set; }
}

Enjoy;)

Upvotes: 0

Related Questions