MVC how to ignore subview model validation

I have a page where I send two view models to the controller, request and assignment. The destination is nested in the request. The user can send a request to us without an appointment.

I use the built-in MVC attributes for view model properties.

My question is: when the user decides to create a query without an assignment, how can I elegantly ignore the validators on the nested Appointment view model and have ModelState.IsValid return true?

if(!viewModel.CreateAppointment) { //ignore the nested view models validation } 
+4
source share
4 answers

You can create your own IgnoreModelError attribute, as shown below, and use two separate buttons in your view for reference only and for meeting.

 // C# public class IgnoreModelErrorAttribute : ActionFilterAttribute { private string keysString; public IgnoreModelErrorsAttribute(string keys) : base() { this.keysString = keys; } public override void OnActionExecuting(ActionExecutingContext filterContext) { ModelStateDictionary modelState = filterContext.Controller.ViewData.ModelState; string[] keyPatterns = keysString.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < keyPatterns.Length; i++) { string keyPattern = keyPatterns[i] .Trim() .Replace(@".", @"\.") .Replace(@"[", @"\[") .Replace(@"]", @"\]") .Replace(@"\[\]", @"\[[0-9]+\]") .Replace(@"*", @"[A-Za-z0-9]+"); IEnumerable<string> matchingKeys = _ modelState.Keys.Where(x => Regex.IsMatch(x, keyPattern)); foreach (string matchingKey in matchingKeys) modelState[matchingKey].Errors.Clear(); } } } [HttpPost] [IgnoreModelErrors("Enquiry.Appointment")] public ActionResult CreateEnquiryOnly(Enquiry enquiry) { // Code for enquiry only. } [HttpPost] public ActionResult CreateAppointment(Enquiry enquiry) { // Code for appointment. } 
+4
source

Well, there is no way to "Elegantly" ignore errors when using standard data attributes.

You have several options. The quick and dirty (i.e. inelegant) way is to simply clear the corresponding errors from ModelState in your controller.

 if (some condition) { ModelState["controlName"].Errors.Clear(); } 

You can also write your own data attributes that use conditional testing. Something like described here:

http://blogs.msdn.com/b/simonince/archive/2011/02/04/conditional-validation-in-asp-net-mvc-3.aspx

A third approach would be to avoid attributes and use a validation framework like FluentValidation

The final option would be to use JavaScript to determine the correct state of the data, and then change the URL of the form to publish to another Action method. You can then decorate the parameters of the action method with Bind attributes to exclude data elements that you do not want. However, I would not recommend this because it requires the client to be involved in the server-side validation process.

+2
source

Here is what I ended up doing.

This allowed me to clear all errors on the nested ViewPointments module.

 if (!viewModel.CreateAppointment) { foreach (var modelError in ModelState) { string propertyName = modelError.Key; if (propertyName.Contains("AppointmentsViewModel")) { ModelState[propertyName].Errors.Clear(); } } } 
+1
source

Another option, instead of nesting the Destination inside the Request, makes the ViewModel for your page containing both the Destination Models and the Requests separately, and then you can use the Bind attribute with Property Include or Exclude to selectively select the Model that you want to link or exclude as shown below.

  Public Class EnquiryViewModel { public Appointment App {get; set;} public Enquiry Enq {get; set; } } [HttpPost] //Only bind Enquiry model and it errors. public ActionResult CreateEnquiryOnly([Bind(Include = "Enq")]EnquiryViewModel enquiry) { if(ModelState.IsValid) { // Code for enquiry only. } } 
0
source

Source: https://habr.com/ru/post/980315/


All Articles