Perform Remote Validation in ASP.NET Core
While performing model validation, at times you need to validate values
entered in client side controls against server side data. Such a validation is
called remote validation. As you might have guessed remote validation uses Ajax
to validate the data. Thus validation is initiated on the client side but
performed on the server side. The outcome of the validation process is sent back
to the client so that the end user can be notified accordingly. In this article
we will learn to implement remote validations in ASP.NET Core MVC and ASP.NET
Core Razor Pages.
Have a look at the following figure that shows the sample data entry form we
use in our example.

The form accepts CustomerID, CompanyName, ContactName, and Country values
from the end user. In addition to typical validations such as required and
string length we also want to restrict certain countries in the Country textbox.
If a country value doesn't meet our criteria an error message is displayed to
the user.
Ok. First of all let's create a model for our application.
public class Customer
{
[Required]
[StringLength(5,MinimumLength =5)]
public string CustomerID { get; set; }
[Required]
[StringLength(40)]
public string CompanyName { get; set; }
[Required]
[StringLength(40)]
public string ContactName { get; set; }
[Required]
[Remote("ValidateCountry","Validator",
ErrorMessage ="Please enter a valid country.")]
public string Country { get; set; }
}
The Customer model class consists of four public properties - CustomerID,
CompanyName, ContactName, and Country. Notice that the Country property is
decorated with [Remote] attribute. The [Remote] attribute allows you to perform
remote validations as explained earlier. It requires a controller name and an
action name. The action specified in the [Remote] attribute implements the
validation logic. If you are using the same validation with multiple models, you
can isolate the action in its own controller. In the preceding code
ValidateCountry action of ValidatorController performs the required validation.
The ErrorMessage property specifies an error message to be displayed to the
user.
The ValidateCountry() action used by the [Remote] attribute is shown below :
public IActionResult ValidateCountry(string country)
{
bool result;
if (country == "USA" || country == "UK"
|| country == "India")
{
result = true;
}
else
{
result = false;
}
return Json(result);
}
The ValidateCountry() action accepts country parameter. Remember that the
name of this parameter must be the same as the model property you are
validating. Inside, you need to implement the country validation logic. In this
simple example, we simple ensure that the country is USA, UK, or India.
Since [Remote] attribute is going to make an Ajax call to ValidateCountry()
action, we return a JsonResult object using the Json() method. The Json() method
accepts a .NET object and converts it into its JSON equivalent. Here, a .NET
boolean value (true / false) will be returned to the client in its JSON form.
We just completed our model and validation action. Now let's move our
attention to the HomeController and its Index view that renders the customer data entry form.
The Index() and OnPost() actions of HomeController are quite straightforward
and are shown below :
public IActionResult Index()
{
return View();
}
[HttpPost]
public IActionResult OnPost(Customer model)
{
if(ModelState.IsValid)
{
ViewData["Message"] = "Success !!!";
}
return View("Index", model);
}
The customer data entry form submits to the OnPost() action. Inside, we
simply set a success message in the ViewData and return the Index view.
The markup of the Index view that renders the data entry form in the
browser is shown below :
@model Customer
<script src="~/scripts/jquery.js"></script>
<script src="~/scripts/jquery.validate.js"></script>
<script src="~/scripts/jquery.validate.unobtrusive.js"></script>
<h1>Add Customer</h1>
<form asp-controller="Home" asp-action="OnPost"
method="post">
<table cellpadding="10" border="1">
<tr>
<td>
<label asp-for="CustomerID">Customer ID :</label>
</td>
<td>
<input type="text" asp-for="CustomerID" />
<span asp-validation-for="CustomerID" class="error">
</span>
</td>
</tr>
<tr>
<td>
<label asp-for="CompanyName">Company Name :</label>
</td>
<td>
<input type="text" asp-for="CompanyName" />
<span asp-validation-for="CompanyName" class="error">
</span>
</td>
</tr>
<tr>
<td>
<label asp-for="ContactName">Contact Name :</label>
</td>
<td>
<input type="text" asp-for="ContactName" />
<span asp-validation-for="ContactName" class="error">
</span>
</td>
</tr>
<tr>
<td>
<label asp-for="Country">Country :</label>
</td>
<td>
<input type="text" asp-for="Country" />
<span asp-validation-for="Country" class="error">
</span>
</td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="Submit" />
</td>
</tr>
</table>
<br />
<div asp-validation-summary="All" class="error">
</div>
<br />
<h2>@ViewData["Message"]</h2>
</form>
Notice the code marked in bold letters. At the top we add a script reference
to three jQuery libraries - jquery.js, jquery.validate.js, and
jquery.validate.unobtrusive.js. These libraries are necessary for the remote
validation to work. Since remote validation needs to make Ajax calls to the
server, it uses functionality provided by these libraries. These libraries are
to be placed inside the Scripts folder under wwwroot. You can also reference
these libraries from a CDN if you so wish.

The <form> POSTs to the OnPost() action of the HomeController. The form also
uses validation tag helper and validation summary tag helper to display the
validation error messages. At the bottom of the page we also display the Message
from the ViewData.
To test the working, set a break point on the ValidateCountry() action and
run the application. Try to enter some country other than USA, UK, and India. If
all goes well you will see the error message displayed in the validation tag
helper as well as the validation summary tag helper.
Validation based on multiple model properties
In the example we just developed, our validation logic involved only Country
property. What if we want to validate a property based on its value as well as
values of a few more properties? Luckily the [Remote] attribute provides a way.
Suppose we want to validate the CompanyName property and our validation logic
also involves the value of Country property.
Have a look at the modified Customer class :
public class Customer
{
[Required]
[StringLength(5,MinimumLength =5)]
public string CustomerID { get; set; }
[Required]
[StringLength(40)]
[Remote("ValidateCompanyName", "Validator",
ErrorMessage = "Please enter a valid company name.",
AdditionalFields ="Country")]
public string CompanyName { get; set; }
[Required]
[StringLength(40)]
public string ContactName { get; set; }
[Required]
[Remote("ValidateCountry","Validator",
ErrorMessage ="Please enter a valid country.")]
public string Country { get; set; }
}
The CompanyName property is now decorated with [Remote] attribute. Notice the
use of AdditionalFields property that specifies a comma separated list of
dependent properties (is case we need only Country property). This time the
ValidateCompanyName() action from the Validator controller performs the
validation and is shown below :
public IActionResult ValidateCompanyName
(string companyname, string country)
{
bool result = true;
if (country == "India" &&
!companyname.EndsWith("Ltd."))
{
result = false;
}
if (country == "USA" &&
!companyname.EndsWith("LLC"))
{
result = false;
}
return Json(result);
}
Note how the ValidateCompanyName() action takes two parameters - one for the
property being validated (companyname) and one for the dependent property
)country). Since we set the AdditionalFields property of the [Remote] attribute
those additional values are passed to the validation action.
Inside, we implement the validation logic that makes use of CompanyName as
well as Country values. The action returns a boolean value as before.
To test our modification, run the application and try entering country as
India and company name that doesn't end with Ltd. Doing so should flash an error
message. The following figure shows a sample run of the validation :

Setting a custom validation message from the validation action
In the preceding examples the view displayed the validation error message as
specified in the ErrorMessage property of the [Remote] attribute. Although this
works well in most of the cases, at times you may need to change the error
message based on your validation logic. You can do that by returning a string
message to the client instead of boolean value. The following code fragment
shows how :
public IActionResult ValidateCountry
(string country)
{
bool result;
string msg = "";
if (country == "USA" || country ==
"UK" || country == "India")
{
return Json(true);
}
else
{
return Json("Invalid country.
Valid values are USA, UK, and India.");
}
}
Once this is done the validation tag helper and validation summary helper
will use this message string as the error message. The following figure shows a
sample run of the above code :

Remote validation in Razor Pages
If you observe the [Remote] attribute, it's clear that it needs a controller
and an action for the sake of validation. There is no Razor Pages specific
version (as yet) of the [Remote] attribute. However, you can still use the
ValidatorController, ValidateCountry() and ValidateCompanyName() actions in the
page model. The following page model class makes this clear :
public class IndexModel : PageModel
{
[Required]
[StringLength(5, MinimumLength = 5)]
[BindProperty]
public string CustomerID { get; set; }
[Required]
[StringLength(40)]
[Remote("ValidateCompanyName",
"Validator", ErrorMessage =
"Please enter a valid company name.",
AdditionalFields = "Country")]
[BindProperty]
public string CompanyName { get; set; }
[Required]
[StringLength(40)]
[BindProperty]
public string ContactName { get; set; }
[Required]
[Remote("ValidateCountry", "Validator",
ErrorMessage = "Please enter a valid country.")]
[BindProperty]
public string Country { get; set; }
public void OnGet()
{
}
[HttpPost]
public void OnPost(Customer model)
{
if (ModelState.IsValid)
{
ViewData["Message"] = "Success !!!";
}
}
As you can see, the CompanyName and Country page model properties are
decorated with the [Remote] attribute in the same way as the model earlier.
That's it for now ! Keep coding !!