← Back to Articles         
Server vs Client-Side Validation

Server vs Client-Side Validation

Published on 27 Sep 2026     12 min read ASP.NET Core MVC
MVC

Server-Side vs Client-Side Validation in ASP.NET Core MVC

1. What is Validation?

Validation means checking whether the data entered by the user is correct before processing or saving it.

For example, suppose we have a registration form:

Name:     [ Syed              ]
Email:    [ syed@gmail.com    ]
Age:      [ 25                ]

             [ Register ]

We may have rules such as:

  • Name is required.
  • Email must be a valid email address.
  • Age must be between 18 and 60.

ASP.NET Core MVC can perform these checks in two places:

                    VALIDATION
                        │
             ┌──────────┴──────────┐
             │                     │
      Client-Side             Server-Side
       Validation              Validation
             │                     │
          Browser                Server

2. Client-Side Validation

Simple Definition

Client-side validation checks user input in the browser before the form is sent to the server.

For example:

User enters invalid data

Age: 15

      ↓

Browser validates it

      ↓

"Age must be between 18 and 60"

      ↓

Request is NOT sent to server

This provides immediate feedback.


3. Server-Side Validation

Simple Definition

Server-side validation checks the submitted data on the server after the request reaches the MVC application.

Browser
   │
   │ POST /Employee/Create
   ▼
ASP.NET Core MVC
   │
   │ Model Binding
   ▼
Validation
   │
   ▼
ModelState.IsValid
   │
   ├── true  → Process / Save
   │
   └── false → Return form with errors

Server-side validation is the authoritative validation because client-side validation can be bypassed.


4. Simple Example

Suppose we have an Employee form containing:

Name
Email
Age

We'll use Data Annotations.

No additional NuGet package is normally required for the basic MVC validation shown below; the validation attributes are provided by .NET, while the standard MVC project includes the client-side validation libraries needed for unobtrusive validation.

EmployeeViewModel

using System.ComponentModel.DataAnnotations;

public class EmployeeViewModel
{
    [Required(ErrorMessage = "Name is required")]
    public string Name { get; set; } = string.Empty;

    [Required(ErrorMessage = "Email is required")]
    [EmailAddress(ErrorMessage = "Enter a valid email address")]
    public string Email { get; set; } = string.Empty;

    [Required]
    [Range(18, 60, ErrorMessage = "Age must be between 18 and 60")]
    public int Age { get; set; }
}

The important point is that the same validation rules can participate in both server-side and client-side validation.

For example:

[Required]

can be checked:

Browser → Client-side validation

AND

Server → Server-side validation

5. Controller

public class EmployeeController : Controller
{
    [HttpGet]
    public IActionResult Create()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Create(EmployeeViewModel model)
    {
        if (!ModelState.IsValid)
        {
            return View(model);
        }

        // Save employee to database

        return RedirectToAction("Success");
    }

    public IActionResult Success()
    {
        return View();
    }
}

The most important code here is:

if (!ModelState.IsValid)
{
    return View(model);
}

6. View

Create.cshtml

@model EmployeeViewModel

<form asp-action="Create" method="post">

    <div>
        <label asp-for="Name"></label>
        <input asp-for="Name" />
        <span asp-validation-for="Name"></span>
    </div>

    <div>
        <label asp-for="Email"></label>
        <input asp-for="Email" />
        <span asp-validation-for="Email"></span>
    </div>

    <div>
        <label asp-for="Age"></label>
        <input asp-for="Age" />
        <span asp-validation-for="Age"></span>
    </div>

    <button type="submit">Save</button>

</form>

@section Scripts
{
    <partial name="_ValidationScriptsPartial" />
}

The following line is particularly important for the normal MVC client-side validation setup:

<partial name="_ValidationScriptsPartial" />

7. How Client-Side Validation Works

Suppose the user enters:

Name:   Syed
Email:  abc
Age:    15

Our model contains:

[EmailAddress]
public string Email { get; set; }

[Range(18, 60)]
public int Age { get; set; }

ASP.NET Core's tag helpers generate validation-related HTML metadata. Conceptually, the generated input contains information similar to:

<input
    name="Age"
    data-val="true"
    data-val-range="Age must be between 18 and 60"
    data-val-range-min="18"
    data-val-range-max="60" />

The browser-side validation libraries read this metadata.

Typical MVC client-side validation uses:

jQuery
      ↓
jQuery Validation
      ↓
jQuery Validation Unobtrusive
      ↓
data-val-* attributes
      ↓
Validation message displayed

So when the user enters:

Age = 15

the browser can immediately show:

Age must be between 18 and 60

without making a normal form POST.


8. _ValidationScriptsPartial.cshtml

A standard MVC project commonly contains:

Views
 └── Shared
      └── _ValidationScriptsPartial.cshtml

It commonly loads scripts along these lines:

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>

<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

Then your page can include them through:

@section Scripts
{
    <partial name="_ValidationScriptsPartial" />
}

Your layout must also render the section, commonly:

@await RenderSectionAsync("Scripts", required: false)

9. What Happens During Server-Side Validation?

Now suppose a request reaches the server.

POST /Employee/Create

Name=Syed
Email=abc
Age=15

ASP.NET Core MVC performs model binding and validation.

Conceptually:

HTTP Request
     ↓
Model Binding
     ↓
EmployeeViewModel created
     ↓
Validation attributes checked
     ↓
ModelState populated
     ↓
Controller Action
     ↓
ModelState.IsValid

For:

[EmailAddress]
public string Email { get; set; }

[Range(18, 60)]
public int Age { get; set; }

both values are invalid.

Therefore:

ModelState.IsValid

will be:

false

and this code runs:

if (!ModelState.IsValid)
{
    return View(model);
}

The form is returned with validation errors.


10. What is ModelState?

ModelState stores information about model binding and validation errors.

For example:

if (!ModelState.IsValid)
{
    return View(model);
}

Suppose:

Email = abc
Age   = 15

Conceptually, ModelState contains:

Email
    Error: Enter a valid email address

Age
    Error: Age must be between 18 and 60

Therefore:

ModelState.IsValid == false

11. Very Important: Client Validation Can Be Bypassed

This is the biggest reason server-side validation is mandatory.

Suppose your website has client-side validation:

Age must be 18–60

A normal browser user enters:

Age = 15

The browser blocks submission.

But someone could bypass the UI completely and send an HTTP request using tools such as an API client or a custom script.

POST /Employee/Create

Name=Syed
Email=test@test.com
Age=15

The browser validation is now irrelevant because the request was constructed directly.

Therefore the server must validate the data again.


12. Why Use Client-Side Validation Then?

Because it improves user experience.

Without client-side validation:

Enter invalid value
        ↓
Submit
        ↓
Network request
        ↓
Server validation
        ↓
Server returns page
        ↓
Show error

With client-side validation:

Enter invalid value
        ↓
Browser validates
        ↓
Show error immediately

It is faster and avoids unnecessary round trips for ordinary user mistakes.


13. Why Server-Side Validation Is Mandatory

Server-side validation protects the application regardless of how the request was created.

              Your MVC Form
                    │
                    ▼
                  Server
                    ▲
                    │
          ┌─────────┼─────────┐
          │         │         │
      Browser    Script    HTTP Client

All requests eventually have to pass the server's validation rules.

That is why:

Client-side validation is mainly for user experience. Server-side validation is required for correctness and security boundaries.


14. Server-Side Only Example

You can disable the client validation scripts simply by not loading them on the page.

For example, remove:

@section Scripts
{
    <partial name="_ValidationScriptsPartial" />
}

Your model can still contain:

[Required]
[Range(18, 60)]
public int Age { get; set; }

and your controller still checks:

if (!ModelState.IsValid)
{
    return View(model);
}

The user submits:

Age = 15

The request reaches the server, server-side validation fails, and the view is returned with the error.

So:

Client-side validation ❌

Server-side validation ✅

still works.


15. Client-Side Only Is Not Sufficient

Suppose you have browser validation but the server ignores validation results:

[HttpPost]
public IActionResult Create(EmployeeViewModel model)
{
    // BAD: ModelState not checked

    SaveEmployee(model);

    return RedirectToAction("Success");
}

Someone bypasses the browser and sends:

Age = 10

The application could save the invalid value.

Therefore this pattern is dangerous:

Client validation only
       ↓
Browser bypassed
       ↓
Server accepts invalid data
       ↓
Database

16. Adding Validation Errors Manually

Sometimes validation cannot be represented conveniently with a simple annotation.

For example:

Employee email must not already exist.

This normally requires checking a database.

[HttpPost]
public async Task<IActionResult> Create(EmployeeViewModel model)
{
    if (!ModelState.IsValid)
    {
        return View(model);
    }

    var exists = await _context.Employees
        .AnyAsync(x => x.Email == model.Email);

    if (exists)
    {
        ModelState.AddModelError(
            nameof(model.Email),
            "Email already exists.");

        return View(model);
    }

    // Save employee

    return RedirectToAction("Success");
}

Here:

ModelState.AddModelError(...)

manually adds a validation error.

This is server-side validation.


17. Field-Level vs Model-Level Errors

You can associate an error with a particular property:

ModelState.AddModelError(
    "Email",
    "Email already exists.");

Then:

<span asp-validation-for="Email"></span>

can display it.

You can also add a model-level error:

ModelState.AddModelError(
    string.Empty,
    "Unable to create employee.");

A validation summary can display such errors:

<div asp-validation-summary="ModelOnly"></div>

A common form therefore looks like:

<form asp-action="Create" method="post">

    <div asp-validation-summary="ModelOnly"></div>

    <label asp-for="Name"></label>
    <input asp-for="Name" />
    <span asp-validation-for="Name"></span>

    <button type="submit">Save</button>

</form>

18. Data Annotations Used by Both

Common validation attributes include:

[Required]
[StringLength(100)]
[Range(18, 60)]
[EmailAddress]
[Phone]
[RegularExpression(...)]

Example:

public class EmployeeViewModel
{
    [Required(ErrorMessage = "Name is required")]
    [StringLength(100)]
    public string Name { get; set; } = string.Empty;

    [Required]
    [EmailAddress(ErrorMessage = "Invalid email")]
    public string Email { get; set; } = string.Empty;

    [Range(18, 60)]
    public int Age { get; set; }
}

Many built-in annotations integrate naturally with both MVC's server validation and its unobtrusive client-validation system.


19. Important Difference: Not Every Validation Rule Automatically Runs Client-Side

This is an important interview point.

Suppose you create a custom validation attribute:

public class AllowedEmailDomainAttribute : ValidationAttribute
{
    protected override ValidationResult? IsValid(
        object? value,
        ValidationContext validationContext)
    {
        var email = value?.ToString();

        if (email != null && email.EndsWith("@company.com"))
        {
            return ValidationResult.Success;
        }

        return new ValidationResult(
            "Only company.com emails are allowed.");
    }
}

Then:

[AllowedEmailDomain]
public string Email { get; set; }

This naturally provides server-side validation.

But custom client-side behavior requires additional integration, such as implementing a client validation adapter/interface or writing JavaScript.

So don't assume:

Custom validation attribute
        =
Automatic client-side validation

20. Remote Validation

Sometimes you want to perform a server check while the user is still filling out the form.

For example:

Email: syed@test.com

        ↓ AJAX

Server checks database

        ↓

"Email already exists"

ASP.NET Core MVC supports remote validation patterns using RemoteAttribute.

Example:

[Remote(
    action: "VerifyEmail",
    controller: "Employee")]
public string Email { get; set; } = string.Empty;

Controller:

public async Task<IActionResult> VerifyEmail(string email)
{
    bool exists = await _context.Employees
        .AnyAsync(x => x.Email == email);

    if (exists)
    {
        return Json("Email already exists.");
    }

    return Json(true);
}

Here the browser triggers a request to the server while validating the field.

However, you should still enforce the rule during the actual POST. Remote validation is a convenience for early feedback, not a replacement for authoritative server validation.


21. Complete Flow

Suppose the user enters:

Name  = ""
Email = "abc"
Age   = 15

The overall flow is:

                    USER
                      │
                      ▼
                MVC FORM
                      │
                      ▼
            Client Validation
                      │
             ┌────────┴────────┐
             │                 │
          Invalid             Valid
             │                 │
             ▼                 ▼
       Show errors          HTTP POST
                               │
                               ▼
                         Model Binding
                               │
                               ▼
                     Server Validation
                               │
                       ModelState.IsValid
                               │
                    ┌──────────┴──────────┐
                    │                     │
                  false                  true
                    │                     │
                    ▼                     ▼
             Return View             Business Logic
             with errors                  │
                                          ▼
                                      Database

22. Server-Side vs Client-Side Validation

Feature Client-Side Server-Side
Runs in Browser Web server
Speed Very fast Requires request
Server round trip Usually no Yes
Immediate feedback Yes No
Can be bypassed Yes Not by bypassing browser UI
Security boundary No Yes
Uses ModelState No Yes
Data Annotations Many supported Yes
JavaScript required Typically yes No
Database validation Usually requires server request Yes
Mandatory No Yes

23. Real-World Example

Consider a registration form:

Name
Email
Password
Confirm Password
Date of Birth

Client-side validation

Good candidates include:

Required fields
Email format
Password length
Confirm password
Basic range checks

These give the user immediate feedback.

Server-side validation

The server should still validate those rules and also handle rules requiring authoritative application state, such as:

Email already registered
Username already exists
Account eligibility
Business rules
Database constraints
Authorization-related conditions

For example:

Email: syed@gmail.com

Client:
"Looks like a valid email address."

Server:
"That email is already registered."

The client can check format locally.

The server checks the actual business state.


24. Validation vs Business Rules

This distinction is useful in larger applications.

Simple input validation:

[Required]
[EmailAddress]
[StringLength(100)]

answers questions such as:

Was a value provided?
Is the format correct?
Is the length acceptable?

Business validation may answer:

Does this customer already exist?
Does this employee have permission?
Is sufficient stock available?
Is this order currently cancellable?

Those rules generally belong in the appropriate server-side application/domain logic rather than relying on browser validation.


25. Important Security Point

Client-side validation should never be trusted as a security mechanism.

Think of it this way:

Client-side validation
        =
Convenience for the user

Server-side validation
        =
Protection of application rules/data

Even server-side validation is only one layer. For critical data integrity, database constraints are also valuable.

For example:

MVC Validation
     ↓
Business Rules
     ↓
Database Constraints

A unique email requirement might ultimately also be protected by a unique database index, because two simultaneous requests could otherwise pass an "email doesn't exist" check before either one commits.


26. Common Interview Question

Q: If we have client-side validation, why do we need server-side validation?

A strong answer:

Client-side validation improves user experience by detecting invalid input immediately in the browser, but it can be bypassed. Server-side validation validates the request after it reaches the application and must be treated as the authoritative validation before processing or saving data.


27. Another Interview Question

Q: Can Data Annotations perform both validations?

Yes, many standard Data Annotations can support both.

For example:

[Required]
[EmailAddress]
[Range(18, 60)]

ASP.NET Core MVC performs server-side validation, while its unobtrusive client-validation integration can expose supported rules to the browser.

But remember:

A custom server-side validation attribute does not automatically mean equivalent JavaScript/client-side validation exists.


28. Key Points

  • Client-side validation runs in the browser.
  • Server-side validation runs on the server.
  • Client-side validation provides fast feedback and better UX.
  • Server-side validation is mandatory because browser validation can be bypassed.
  • ASP.NET Core MVC stores binding and validation errors in ModelState.
  • Check:
if (!ModelState.IsValid)
{
    return View(model);
}
  • Standard Data Annotations include:
[Required]
[StringLength]
[Range]
[EmailAddress]
[RegularExpression]
  • Client-side MVC validation commonly depends on:
<partial name="_ValidationScriptsPartial" />
  • asp-validation-for displays property-specific errors.
  • asp-validation-summary displays validation summaries.
  • Use ModelState.AddModelError() for additional server-side errors.
  • Database/business validation should be enforced on the server.
  • Never rely only on client-side validation.

Easy way to remember

Client-side = Better user experience

Server-side = Trusted validation

Best practice = Use both

← Back to Articles