Search This Blog

Sunday 8 December 2019

Validate nested class in MVC with Validator.TryValidateObject()

using System.ComponentModel.DataAnnotations;


public class ValidateModel
{
    static string result = string.Empty;
    public static string Validate(object obj)
    {
        var context = new ValidationContext(obj, serviceProvider: null, items: null);
        var results = new List<ValidationResult>();
        var isValid = Validator.TryValidateObject(obj, context, results, true);
        if (!isValid)
            foreach (var validationResult in results)
                result += validationResult.ErrorMessage;
        foreach (var prop in obj.GetType().GetProperties())
        {
            if (prop.PropertyType == typeof(string) || prop.PropertyType.IsValueType) continue;
            var value = prop.GetValue(obj);
            if (value == null) continue;
            var isEnumerable = value as IEnumerable;
            if (isEnumerable == null)
                Validate(value);
            else
                foreach (var nestedModel in isEnumerable)
                    Validate(nestedModel);
        }
        return result;
    }
}

Note:- 
MVC ModelBinder is doing all complex type DataAnnotations validation itself when you checked ModelState.IsValid in the action but it's failed when you pass the object instead of model.

In that case, you need to call the Validator.TryValidateObject() function but it's also failed to validate the complex/nested class DataAnnotations.

The above example is the solution for overcome to this issue using recursive function call.


=>Sample Model
public class RegistrationRequest
{
    public object body { get; set; }
}
public class Registration
{
    public int Id { get; set; }
    [Required]
    public string FirstName { get; set; }
    public string MiddleName { get; set; }
    [Required]
    public string LastName { get; set; }
    public Address address { get; set; }
    public List<PastHistory> pastHistory { get; set; }
}
public class Address
{
    [Required]
    public string Address1 { get; set; }
    [Required]
    public string Address2 { get; set; }
    public string Address3 { get; set; }
    [Required]
    public string State { get; set; }
    [Required]
    public string City { get; set; }
    [Required]
    public string Pincode { get; set; }
}
public class PastHistory
{
    [Required]
    public string ComapnyName { get; set; }
}

=>Sample Controller
[HttpPost]
public HttpResponseMessage Registration(RegistrationRequest reg)
{
    Registration registration = JsonConvert.DeserializeObject<Registration>(reg.body.ToString());

    string validateResult = ValidateModel.Validate(registration);
    if (!string.IsNullOrEmpty(validateResult))
        return Request.CreateErrorResponse(HttpStatusCode.BadRequest, validateResult);
    else
        return Request.CreateResponse(HttpStatusCode.OK);
}

=>Sample JSON
   "body":{ 
      "Id":"1",
      "FirstName":"Ram",
      "MiddleName":"",
      "LastName":"",
      "Address":{ 
         "Address1":"",
         "Address2":"",
         "Address3":"",
         "State":"",
         "City":"",
         "Pincode":""
      },
      "PastHistory":[ 
         { 
            "ComapnyName":""
         }
      ]
   }
}



How to get all Errors from modelState in ASP.Net MVC?


[HttpPost]
public HttpResponseMessage Registration(RegistrationRequest reg)
{
    if (ModelState.IsValid)
    {
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    IEnumerable<string> errors = ModelState.Values.SelectMany(v => v.Errors.Select(b => b.ErrorMessage));
    string strErrors = string.Join("; "errors);

    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, strErrors);
}


OR


[HttpPost]
public HttpResponseMessage Registration(RegistrationRequest reg)
{
    if (ModelState.IsValid)
    {
        return Request.CreateResponse(HttpStatusCode.OK);
    }

    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}

Saturday 7 December 2019

OR condition in regular expression

=>Web API
using System.ComponentModel.DataAnnotations;

[RegularExpression(@"^(Y)|(N)$", ErrorMessage = "IsHandicap can only be Y or N.")]
public string IsHandicap{ getset; }

=>C Sharp
using System.Text.RegularExpressions;


string regex = @"^(Y)|(N)$";
string inputString = "Y";
Match match = Regex.Match(inputString, regex);

=>Java Script
<script>
    function Validate() {
        var text = document.getElementById("TextBox1").value;
        var pattern = "^(Y)|(N)$";
        var result = text.match(pattern);
        if (!result)
            alert("IsHandicap can only be Y or N.");
    }
</script>

<asp:TextBox ID="TextBox1" runat="server" ClientIDMode="Static"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="return Validate();" />


Note:- Input string only valid when IsHandicap field value "Y" and "N".


[] - Find any character matching between in the square brackets.
() - Find matching character or word in the brackets.

Regular expression for mobile number with fix country code

=>Web API
using System.ComponentModel.DataAnnotations;

[RegularExpression(@"^(91)?\d{10}$", ErrorMessage = "invalid country code or mobile no.")]   
public string mobileno { getset; }

=>C Sharp

using System.Text.RegularExpressions;

string regex = @"^(91)?\d{10}$";
string inputString = "919876543210";
Match match = Regex.Match(inputString, regex);

=>Java Script
<script>
    function Validate() {
        var text = document.getElementById("TextBox1").value;
        var pattern = "^(91)?\d{10}$";
        var result = text.match(pattern);
        if (!result)
            alert("invalid country code or mobile no.");
    }
</script>

<asp:TextBox ID="TextBox1" runat="server" ClientIDMode="Static"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="Button" OnClientClick="return Validate();" />


Note:- Input string only valid when mobile no passed with Indian country code i.e. 91.