Skip to main content

Validate Input

  • 11 minutes to read

Use standard Blazor EditForm to validate data input. Inside the form, you can display a DevExpress Form Layout component or any DevExpress standalone data editor. The EditForm reads data annotation attributes defined in a model and indicates any errors.

Form Layout Validation

The following table lists data editors and their properties you can validate in the EditForm:

Data Editor

Property

DxCalendar

SelectedDate, SelectedDates

DxCheckBox

Checked

DxComboBox

Text, Value

DxDateEdit

Date

DxDropDownBox

Value

DxListBox

Values

DxMaskedInput

Value

DxMemo

Text

DxRadio

GroupValue

DxRadioGroup

Value

DxSpinEdit

Value

DxTagBox

Tags, Values

DxTextBox

Text

Important

You should not rely on form validation alone to secure your Blazor-powered app. Form validation is designed to improve usability. A threat actor can bypass validation and send malicious data to the server. To minimize security related threats/risks, you must validate user input using multiple strategies. Refer to the following topic for more information: Validate User Input.

Standard Validation Mechanism

If users submit an EditForm, they initiate input validation based on the edit context. DevExpress Blazor Editors support this standard data validation technique. For additional information on how validation works in Blazor, refer to Microsoft documentation: Forms and validation.

The sections below describe how to set up validation for DevExpress Blazor Editors.

Set Up a Validation Model

Create a model and apply data annotation attributes to model fields.

using System.ComponentModel.DataAnnotations;

public class MyModel {
    [Required]
    [StringLength(10, ErrorMessage = "Name is too long.")]
    public string Name { get; set; }
    // ...
}

Declare EditForm markup and assign a model object to the EditForm’s Model property. The edit context is constructed based on this model. To supply the edit context explicitly, assign it to the EditContext property and do not specify the Model property.

<EditForm Model="@model">
</EditForm>

@code {
    private MyModel model = new MyModel();
    // ...
}

Add a DataAnnotationsValidator component to enable validation based on annotation attributes.

<EditForm Model="@model">
    <DataAnnotationsValidator />
</EditForm>

Set Up Components for Validation

Add standalone data editors or a Form Layout with data editors to the EditForm. Use the @bind attribute to implement two-way binding between editor properties and model fields with data annotations. New input triggers edit context updates.

<EditForm Model="@model" Context="EditFormContext">
    <DataAnnotationsValidator />
    <DxFormLayout Context="FormLayoutContext">
        <DxFormLayoutItem Caption="Name:" ColSpanMd="6" >
            <DxTextBox @bind-Text="@model.Name" />
        </DxFormLayoutItem >
    </DxFormLayout>
    @*...*@
</EditForm>

Display Validation Results

Editors can notify users about validation results in a number of ways: icons, colored outlines, and validation messages.

Validation Icons and Colored Outlines

Blazor data editors can display validation icons and colored outlines based on validation results. Editors with default settings display red outlines and error icons Error when validation fails, but do not indicate the success status for valid inputs.

You can use the following properties to change how editors display their validation status:

ShowValidationIcon

Use ShowValidationIcon global option or an editor’s ShowValidationIcon property to specify whether an editor shows a validation icon: Success or Error. The following code disables validation icons in the Text Box:

<DxTextBox @bind-Text="@model.Name"
        ShowValidationIcon="false" />
ShowValidationSuccessState

Use The ShowValidationSuccessState global option or an editor’s ShowValidationSuccessState property to specify whether an editor indicates successful validation. It displays a green outline and can show a success icon Success (if the ShowValidationIcon is set to true). The following code enables a green outline for valid input in the Text Box.

<DxTextBox @bind-Text="@model.Name"
        ShowValidationSuccessState="true" />

Note that when ShowValidationSuccessState is true, and ShowValidationIcon is false, only green outlines indicate the success status.

The following table demonstrates different configurations:

Valid Value

Invalid Value

Default configuration
ShowValidationIcon = "true"
ShowValidationSuccessState = "false"

Valid Input

Invalid Input

ShowValidationIcon = "false"
ShowValidationSuccessState = "false"

Valid Input

Invalid Input

ShowValidationIcon = "true"
ShowValidationSuccessState = "true"

Valid Input

Invalid Input

ShowValidationIcon = "false"
ShowValidationSuccessState = "true"

Valid Input

Invalid Input

Run Demo: Form Validation - Form Layout

Validation Messages

Use the ValidationMessage component to display messages for individual data editors or the ValidationSummary component to summarize validation messages.

<DxFormLayout Context="FormLayoutContext">
    @*...*@
    <DxFormLayoutItem ColSpanMd="12">
        <ValidationSummary />
    </DxFormLayoutItem>
</DxFormLayout>

Run Demo: Form Validation - Form Layout

Submit a Form

Add a DxButton or DxToolbarItem object to the markup and set the object’s SubmitFormOnClick property to true. The form is submitted when a user clicks this button or item.

<DxFormLayout Context="FormLayoutContext">
    @*...*@
    <DxFormLayoutItem>
        <DxButton SubmitFormOnClick="true" Text="Submit" RenderStyle="@ButtonRenderStyle.Secondary" />
    </DxFormLayoutItem>
</DxFormLayout>

If you want to respond to form submission, specify the EditForm‘s OnValidSubmit and OnInvalidSubmit callbacks. They are triggered when the form passed and failed validation, respectively. For instance, you can post valid values to an underlying data source. Alternatively, you can specify the OnSubmit callback to check field values and trigger validation manually.

<EditForm Model="@model" 
          Context="EditFormContext"
          OnValidSubmit="@HandleValidSubmit" 
          OnInvalidSubmit="@HandleInvalidSubmit">
    @*...*@
</EditForm>

Custom Validation

You can implement custom validation logic if the standard validation methods do not meet your requirements.

Validation Attribute

Follow the steps below to create a custom validation attribute:

  1. Create a ValidationAttribute class descendant.
  2. Override the IsValid method to implement custom validation logic. This method has two overloads: one overload accepts only the object that should be validated; the other also accepts a ValidationContext object that stores additional information about the validation operation.
  3. Apply the AttributeUsageAttribute to the class. Specify where and how your new custom attribute can be used.
  4. Apply the custom attribute to a model field.
using System.ComponentModel.DataAnnotations;

public class Starship {
    // ...

    [DateInPastAttribute(ErrorMessage = "The Production Date value cannot be later than today.")]
    public DateTime ProductionDate { get; set; }
}

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, 
                AllowMultiple = false)]
public class DateInPastAttribute: ValidationAttribute {
    public override bool IsValid(object value) {
        return (DateTime)value <= DateTime.Today;
    }
}

For more information, refer to Microsoft documentation: Custom attributes.

Validator Component

Follow the steps below to create a custom validation component:

  1. Create a ComponentBase descendant (CustomValidation in the example below).
  2. Implement a property that reflects the Edit Form’s EditContext. Decorate it with the CascadingParameter attribute.
  3. In the OnInitialized method, create a ValidationMessageStore instance that stores a list of form errors.
  4. Implement the DisplayErrors method to receive validation errors and save them to a dictionary.
  5. Implement the ClearErrors method to clear the list of error messages.
  6. Place the CustomValidation component to the Edit Form.
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;

namespace DxBlazorApplication1.Data {
    public class CustomValidation : ComponentBase {
        [CascadingParameter]
        private EditContext? CurrentEditContext { get; set; }
        private ValidationMessageStore? messageStore;
        protected override void OnInitialized() {
            messageStore = new(CurrentEditContext);
            CurrentEditContext.OnValidationRequested += (s, e) => messageStore?.Clear();
            CurrentEditContext.OnFieldChanged += (s, e) => messageStore?.Clear(e.FieldIdentifier);
        }
        public void DisplayErrors(Dictionary<string, List<string>> errors) {
            if (CurrentEditContext is not null) {
                foreach (var err in errors) {
                    messageStore?.Add(CurrentEditContext.Field(err.Key), err.Value);
                }
                CurrentEditContext.NotifyValidationStateChanged();
            }
        }
        public void ClearErrors() {
            messageStore?.Clear();
            CurrentEditContext?.NotifyValidationStateChanged();
        }
    }
}

For more information, refer to Microsoft documentation: Validator components.

Disable Validation

Set an editor’s ValidationEnabled to false to disable validation.

The following code disables input validation in the List Box component:

<EditForm Model="@model">
    <DataAnnotationsValidator />
    @*...*@
    <DxListBox Data="@model.Names" 
               @bind-Values="@Values" 
               ValidationEnabled="false"/>
    @*...*@
</EditForm>

You can also disable validation for editors placed in the Grid or TreeList component. These components have their own ValidationEnabled properties.

Examples

See sections below for different editor validation examples.

Standalone Data Editors

The following example validates user input in a standalone Text Box, Combo Box, Spin Edit, and Date Edit. The ValidationMessage component displays error messages for each editor.

Validate Input in Data Editors

<EditForm Model="@starship" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit">
    <DataAnnotationsValidator />
    <div class="row">
        <div class="col-md-6" style="padding-bottom: 12px">
            <label for="identifier">Identifier: </label>
            <DxTextBox Id="identifier" @bind-Text="@starship.Identifier" />
            <ValidationMessage For="@(() => starship.Identifier)" />
        </div>
        <div class="col-md-6" style="padding-bottom: 12px">
            <label for="classification">Primary Classification: </label>
            <DxComboBox Id="classification" NullText="Select classification ..."
                        ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
                        Data="@(new List<Classification>() { new Classification(1, "Defense"),
                                                             new Classification(2, "Exploration"),
                                                             new Classification(3, "Diplomacy") })"
                        TextFieldName="Value"
                        ValueFieldName="Id"
                        @bind-Value="@starship.Classification" />
            <ValidationMessage For="@(() => starship.Classification)" />
        </div>
        <div class="col-md-6" style="padding-bottom: 12px">
            <label for="accommodation">Maximum Accommodation: </label>
            <DxSpinEdit Id="accommodation" @bind-Value="@starship.MaximumAccommodation" />
            <ValidationMessage For="@(() => starship.MaximumAccommodation)" />
        </div>
        <div class="col-md-6" style="padding-bottom: 12px">
            <label for="productionDate">Production Date: </label>
            <DxDateEdit @bind-Date="@starship.ProductionDate" />
            <ValidationMessage For="@(() => starship.ProductionDate)" />
        </div>
        <div class="col-md-12">
            <DxButton SubmitFormOnClick="true" Text="Submit" RenderStyle="@ButtonRenderStyle.Secondary" />
        </div>
    </div>
</EditForm>

@code {
    private Starship starship = new Starship();

    private void HandleValidSubmit() {
        Console.WriteLine("OnValidSubmit");
    }
    private void HandleInvalidSubmit() {
        Console.WriteLine("OnInvalidSubmit");
    }
}

Run Demo: Form Validation - Custom Form

Form Layout

The following example validates user input in the Form Layout component with four layout items. These items contain the following data editors: Text Box, Combo Box, Spin Edit, and Date Edit.

One layout item contains the ValidationSummary component that displays all the error messages. The last layout item contains the Button that submits the form.

Validate Input in Form Layout

@using System.ComponentModel.DataAnnotations
<div class="cw-880">
    <EditForm Model="@starship"
              OnValidSubmit="@HandleValidSubmit"
              OnInvalidSubmit="@HandleInvalidSubmit"
              Context="EditFormContext">
        <DataAnnotationsValidator/>
        <DxFormLayout>
            <DxFormLayoutItem Caption="Identifier:" ColSpanMd="6">
                <DxTextBox @bind-Text="@starship.Identifier" ShowValidationIcon="true"/>
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Primary Classification:" ColSpanMd="6">
                <DxComboBox NullText="Select classification ..."
                            ClearButtonDisplayMode="DataEditorClearButtonDisplayMode.Auto"
                            Data="classifications"
                            @bind-Value="@starship.Classification"
                            ShowValidationIcon="true"/>
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Maximum Accommodation:"
                              ColSpanMd="6">
                <DxSpinEdit Id="accommodation" ShowValidationIcon="true"
                            @bind-Value="@starship.MaximumAccommodation"/>
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Production Date:"
                              ColSpanMd="6">
                <DxDateEdit @bind-Date="@starship.ProductionDate" ShowValidationIcon="true"/>
            </DxFormLayoutItem>
            <DxFormLayoutItem Caption="Description:"
                              ColSpanMd="12">
                <DxMemo @bind-Text="@starship.Description" ShowValidationIcon="true"/>
            </DxFormLayoutItem>
            <DxFormLayoutItem ColSpanMd="12">
                <DxButton SubmitFormOnClick="true"
                          Text="Submit"
                          RenderStyle="ButtonRenderStyle.Secondary"/>
            </DxFormLayoutItem>
            <DxFormLayoutItem ColSpanMd="12">
                <ValidationSummary/>
            </DxFormLayoutItem>
        </DxFormLayout>
        <div class="row w-100 mx-0">
            <p class="demo-text col-12 mt-2">
                Form Validation State: <b>@FormValidationState</b>
            </p>
        </div>
    </EditForm>
</div>

@code {
    string FormValidationState = @"Press the ""Submit"" button to validate the form.";
    Starship starship = new Starship() { ProductionDate = DateTime.Now + TimeSpan.FromDays(1) };
    List<string> classifications = new List<string>() { "Defense", "Exploration", "Diplomacy" };
    void HandleValidSubmit() {
        FormValidationState = @"Form data is valid";
    }
    void HandleInvalidSubmit() {
        FormValidationState = @"Form data is invalid";
    }
    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false)]
    public class DateInPastAttribute : ValidationAttribute {
        public override bool IsValid(object value) {
            return (DateTime)value <= DateTime.Today;
        }
    }
    public class Starship {
        [Required(ErrorMessage = "The Identifier value should be specified.")]
        [StringLength(16, ErrorMessage = "The Identifier exceeds 16 characters.")]
        public string Identifier { get; set; }
        [Required(ErrorMessage = "The Primary Classification value should be specified.")]
        public string Classification { get; set; }
        [Range(1, 100000, ErrorMessage = "The Maximum Accommodation value should be a number between 1 and 100,000.")]
        public int MaximumAccommodation { get; set; }
        [Required]
        [DateInPastAttribute(ErrorMessage = "The Production Date value cannot be later than today.")]
        public DateTime ProductionDate { get; set; }
        [Required(ErrorMessage = "The Description should be specified.")]
        public string Description { get; set; }
    }
}

Run Demo: Form Validation - Form Layout

Data Editors Inside Another Component

To validate user input in a data editor that is placed in another Blazor component, follow the steps below:

  1. Create a custom Blazor component and add a data editor. Define parameters that are passed to the editor’s <PropertyName> and <PropertyName>Expression properties and handle the <PropertyName>Changed event as shown below. The following code snippet creates MyComponent with a Text Box:

    <DxTextBox Text="@MyValue" TextChanged="@((v) => MyValue = v)" TextExpression="@MyValueExpression" />
    
    @code {
        private string _value;
    
        [Parameter]
        public string MyValue {
            get => _value;
            set {
                if (_value == value) return;
                _value = value;
                MyValueChanged.InvokeAsync(value);
            }
        }
    
        [Parameter]
        public EventCallback<string> MyValueChanged { get; set; }
    
        [Parameter]
        public Expression<Func<string>> MyValueExpression { get; set; }
    }
    
  2. Register the System.Linq.Expressions namespace in the _Imports.razor file to use the Expression class.

    @using System.Linq.Expressions
    
  3. Apply data annotation attributes to model fields. Add MyComponent to EditForm.

    <EditForm Model="@customer" OnValidSubmit="@HandleValidSubmit" OnInvalidSubmit="@HandleInvalidSubmit" 
            Context="EditFormContext">
        <DataAnnotationsValidator />
        <div class="container">
            <div class="col">
                <div class="row"><h5>@nameof(customer.FirstName)</h5></div>
                <div class="row">
                    <div class="form-group">
                        <MyComponent @bind-MyValue="@customer.FirstName" />
                        <ValidationMessage For="@(() => customer.FirstName)" />
                    </div>
                </div>
            </div>
    
            <div class="col">
                <div class="row"><h5>@nameof(customer.LastName)</h5></div>
                <div class="row">
                    <div class="form-group">
                        <MyComponent @bind-MyValue="@customer.LastName" />
                        <ValidationMessage For="@(() => customer.LastName)" />
                    </div>
                </div>
            </div>
            <div class="row">
                <div class="col">
                    <div class="form-group ">
                        <DxButton SubmitFormOnClick="true" Text="Submit" 
                                  RenderStyle="@ButtonRenderStyle.Primary" />
                    </div>
                </div>
            </div>
        </div>
    </EditForm>
    

Validate Editors in Another Component

See Also