See a mistake here? Or something missing? Let me know!
Use C# Attributes from the System.ComponentModel.DataAnnotations namespace to add server-side and client-side validation.
Tip: Keep your view model separate from your database model, because the same data attributes will do two different things: Set validation rules, and set characteristics of the database columns when you use code-first database generation. If you want to use only a single model, you could avoid the data-attributes altogether and only use custom validation attributes to create validation rules.
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace ValidationAttributesProject.Entities
{
public class Customer
{
public long CustomerId { get; set; }
[StringLength(50)]
public string Name { get; set; }
[EmailAddress]
public string Email { get; set; }
[Phone]
public string Phone { get; set; }
public int YearToDateOrderCount { get; set; }
[RegularExpression(@"\d\d?/\d\d?/\d\d\d\d")]
[MinDate(2000,1,1)]
public string AccountCreationDate { get; set; }
[RegularExpression(@"\d\d?/\d\d?/\d\d\d\d")]
// could do another custom validation attribute to make sure this date comes after AccountCreationDate
public string FirstTransactionDate { get; set; }
}
}
Notice the [MinDate(2000,1,1)]
attribute – that’s a custom one that validates that the string input for this property indicates a date that is not before January 1, 2000. Here is how to define that custom attribute:
using System.ComponentModel.DataAnnotations;
using System.Text.RegularExpressions;
namespace ValidationAttributesProject.Entities
{
public class MinDateAttribute : ValidationAttribute
{
public MinDateAttribute(int year, int month, int day)
{
Year = year;
Month = month;
Day = day;
}
public int Year { get; set; }
public int Month { get; set; }
public int Day { get; set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// Make sure that the input is not earlier than the date on the validation attribute
string dateInput = (string)value;
(int year, int month, int day) = getYearMonthDayIntegers(dateInput);
if ((year * 10000 + month * 100 + day) < (Year * 10000 + Month * 100 + Day))
return new ValidationResult($"Date must be no earlier than {Month}/{Day}/{Year}.");
else
return ValidationResult.Success;
}
Regex dateRegex = new Regex(@"(?<Month>\d{1,2})/(?<Day>\d{1,2})/(?<Year>\d{4})");
private (int, int, int) getYearMonthDayIntegers(string date)
{
Match m = dateRegex.Match(date);
return (int.Parse(m.Groups["Year"].Value),
int.Parse(m.Groups["Month"].Value),
int.Parse(m.Groups["Day"].Value));
}
}
}
Shown below is the View. Notice these things:
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<span asp-validation-for="CustomerId" class="text-danger"></span>
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
@model ValidationAttributesProject.Entities.Customer
@{
ViewData["Title"] = "View";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>View</h1>
<h4>Customer</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="View">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="CustomerId" class="control-label"></label>
<input asp-for="CustomerId" class="form-control" />
<span asp-validation-for="CustomerId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Phone" class="control-label"></label>
<input asp-for="Phone" class="form-control" />
<span asp-validation-for="Phone" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="YearToDateOrderCount" class="control-label"></label>
<input asp-for="YearToDateOrderCount" class="form-control" />
<span asp-validation-for="YearToDateOrderCount" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AccountCreationDate" class="control-label"></label>
<input asp-for="AccountCreationDate" class="form-control" />
<span asp-validation-for="AccountCreationDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FirstTransactionDate" class="control-label"></label>
<input asp-for="FirstTransactionDate" class="form-control" />
<span asp-validation-for="FirstTransactionDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
@section Scripts {
@{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
And here are the contents of _ValidationScriptsPartial.cshtml
:
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
Finally, note the use of ModelState.IsValid
in the Controller action:
// POST: Customer/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Customer model)
{
if (!ModelState.IsValid)
{
// Validation rules did not pass
return View(model);
}
else
{
// Code here for valid input scenario
return RedirectToAction(nameof(Index));
}
}
Other helps:
Leave a Reply