Forms in Blazor

In this post, we’re going to see how to create forms in Blazor and how to send the information to the backend for processing. 

This allows us to display different messages to the user depending on whether the data is correct or not.

 

 

1 - Use Case

For this use case, we’re going to add a contact form to our website.

To do this, the first thing we need to do is create an endpoint in the backend that will receive the information.

Something as simple as the following object will work for our example:

public class ContactDto
{
    public string Name { get; set; }
    public string Surname { get; set; }
    public string Email { get; set; }
    public string Message { get; set; }
}

And in the endpoint, a simple return true will be enough for now. Remember, we’re testing the frontend here, not the backend.

[ApiController]
[Route("api/[controller]")]
public class ContactController : Controller
{
    [HttpPost]
    public Task<ResultDto<ContactResponse>> Post(ContactDto Contacto)
    {
        return Task.FromResult(new ContactResponse()
        {
            MessageSent = true
        }.Success()
        .MapDto(x => x));
    }
}

public class ContactResponse
{
    public bool MessageSent { get; set; }
}

Note: Remember that in this project we use railway oriented programming. 

 

 

2 - Creating a Form in Blazor

First of all, we have to create a component for our form, and there we’ll create the form.

 

In this case, it’s a component inside our main page, but in many other circumstances a form would be a standalone page, like for product creation or product booking, which are common elements in the professional world. 

 

The first thing we have to do is create a private property _contactoDto that references the type we just created. We’ll use this property to bind the fields in the form to the actual object.

 

We’ll also create a method called Enviar which will be executed when the user submits the form.

Remember that we can do it in the .razor file itself using the @code block, or in a partial class. Personally, I find it easier to modify in a partial class. 

public partial class Contacto
{
    private ContactDto _contact { get; set; } = new ContactDto();

    private void Enviar()
    {

    }
}

 

 

3 - Defining a Form in Blazor

Now, we just need to create our form. For this we’ll use the component that Microsoft provides, called EditForm. Here, we can use the Model attribute to indicate our _contactoDto property, as well as the OnSubmit callback to call the method we’ve defined.

<h3>Contacto</h3>
<EditForm Model="_contact" OnSubmit="Enviar">
    // Rest of the form
    <button type="submit">Enviar formulario </button>
</EditForm>

As you can see, we haven't specified the method attribute as we would in a normal HTML form. That’s because it won’t be sent in the same way; sending the form will call our method, where we have to write how to send the data to the backend.

 

3.1 - Elements of a Form in Blazor

For our form fields, we're also going to use components provided directly by Microsoft with the language.

 

Although we can use native HTML form elements, I recommend using Blazor's components. That way, you get various default validations. For example, using <inputnumber …> is like <input type="number"…>, same for date, checkbox, etc.

 

Each of these components has a property called @bind-Value that allows us to bind that particular field to a property on our object.

<h3>Contacto</h3>
<EditForm Model="_contact" OnSubmit="Enviar">
    <div class="form-group row">
        <label for="name" class="col-md-2 col-form-label">Nombre:</label>
        <div class="col-md-10">
            <InputText id="name" class="form-control" @bind-Value="_contact.Name" />
        </div>
    </div>
    <div class="form-group row">
        <label for="surname" class="col-md-2 col-form-label">Apellido:</label>
        <div class="col-md-10">
            <InputText id="surname" class="form-control" @bind-Value="_contact.Surname" />
        </div>
    </div>
    <div class="form-group row">
        <label for="email" class="col-md-2 col-form-label">Email:</label>
        <div class="col-md-10">
            <InputText id="email" class="form-control" @bind-Value="_contact.Email" />
        </div>
    </div>
    <div class="form-group row">
        <label for="message" class="col-md-2 col-form-label">mensaje:</label>
        <div class="col-md-10">
            <InputTextArea rows="5" id="message" class="form-control" @bind-Value="_contact.Message" />
        </div>
    </div>
    <button type="submit">Enviar formulario </button>
</EditForm>

Also, as you can see, we can nest HTML elements inside the EditForm component and assign CSS classes.

Now, in our Enviar method, we just need to make an HTTP call to the backend, indicating it’s a POST.

public partial class Contacto
{
    [Inject]
    private IHttpClientFactory ClientFactory { get; set; }
    private ContactDto _contact { get; set; } = new ContactDto();

    private async Task Enviar()
    {
        HttpClient client = ClientFactory.CreateClient("BackendApi");
        HttpResponseMessage result = await client.PostAsJsonAsync($"api/contact", _contact);
        //We’ll work with the result later
        var contactResponse = await result.Content.ReadFromJsonAsync<ResultDto<ContactResponse>>();
    }
}

 

 

 

4 - Form Validation in Blazor

We have several options to validate a form.

 

4.1 - Manual Form Validation in Blazor

If we have assigned the @bind-Value attribute correctly, each property of our object will have the value entered by the user. So in our Enviar method, we could check that each field has the values we need and, if not, not send the form to the backend.

private async Task Enviar()
{
    if (string.IsNullOrEmpty(_contact.Message))
    {
        //don’t send the information
    }
    else
    {
        HttpClient client = ClientFactory.CreateClient("BackendApi");
        HttpResponseMessage result = await client.PostAsJsonAsync($"api/contact", _contact);
        //We’ll work with the result later
        var contactResponse = await result.Content.ReadFromJsonAsync<ResultDto<ContactResponse>>();
    }
}

 

4.2 - Validation Using Annotations

Additionally, we can validate forms using annotations in our class.

 

To do this, the first thing is to install the System.ComponentModel.Annotations library. This allows us to include attributes on our properties, which serve to validate those form elements.

 

In this use case, we need to ensure both the name and the message content are required, as well as ensure the email is a valid email.

public class ContactDto
{
    [Required(ErrorMessage = "Por favor indica tu nombre")]
    public string Name { get; set; }
    public string Surname { get; set; }
    [RegularExpression("^[a-zA-Z0-9_\\.-]+@([a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,6}$", ErrorMessage = "Debes indicar un email válido")]
    public string Email { get; set; }
    [Required(ErrorMessage = "El contenido del mensaje es obligatorio")]
    public string Message { get; set; }
}

Now we can modify our form by adding the <DataAnnotationsValidator/> component along with ValidationMessage, which will display the error message we specified.

<h3>Contacto</h3>
<EditForm Model="_contact" OnSubmit="Enviar">
    <DataAnnotationsValidator />
    <div class="form-group row">
        <label for="name" class="col-md-2 col-form-label">Nombre:</label>
        <div class="col-md-10">
            <InputText id="name" class="form-control" @bind-Value="_contact.Name" />
            <ValidationMessage For="@(() => _contact.Name)" />
        </div>
    </div>
    <div class="form-group row">
        <label for="surname" class="col-md-2 col-form-label">Apellido:</label>
        <div class="col-md-10">
            <InputText id="surname" class="form-control" @bind-Value="_contact.Surname" />
        </div>
    </div>
    <div class="form-group row">
        <label for="email" class="col-md-2 col-form-label">Email:</label>
        <div class="col-md-10">
            <InputText id="email" class="form-control" @bind-Value="_contact.Email" />
            <ValidationMessage For="@(() => _contact.Email)" />
        </div>
    </div>
    <div class="form-group row">
        <label for="message" class="col-md-2 col-form-label">mensaje:</label>
        <div class="col-md-10">
            <InputTextArea rows="5" id="message" class="form-control" @bind-Value="_contact.Message" />
            <ValidationMessage For="@(() => _contact.Message)" />
        </div>
    </div>
    <button type="submit">Enviar formulario </button>
</EditForm>

And this is what we’ll see.

data anotations blazor

And if we try to send the message, we won’t be able to until we fix the errors. 

Note: We’ll get the same result if we try to call the API directly.

 

 

5 - Working with Server Response

Finally, when we get the server’s response, we need to notify the user that everything has worked correctly (or show errors if there are any).

 

As you may have guessed, in Blazor we don’t have ajax like we do in conventional web apps to asynchronously call the server. Here we’ve done it with our HTTP call inside our Enviar method.

 

In our case, it returns ResultDto<contactoResponse>. What we need to do is check if the result is true and, if it is, display a message.

 

Personally, when dealing with a contact form, I like to hide the form and display a message instead, to reassure the user that their message has been sent.

 

First, create two CSS styles, one to show and one to hide content.

<style>
    .oculto{
        display: none;
    }
    .visible{
        display: inherit;
    }
</style>

We then add a block with our hidden message, and also assign the CSS rule to our form.

But instead of applying the rule directly, we use a variable that points to the CSS rule.

<h3>Contacto</h3>
<div class="alert alert-success @MessageBoxCss" role="alert">
    <h4 class="alert-heading">Mensaje enviado correctamente</h4>
    <p>Gracias por contactar con el equipo de netmentor, nos pondremos en contacto lo mas rápido posible.</p>
</div>
<div class="@FormCss">
    <EditForm Model="_contact" OnSubmit="Enviar" clas="@FormCss">
        ///Resto del formulario
        <button type="submit">Enviar formulario </button>
    </EditForm>
</div>

Of course, in our C# code we need to define these variables and assign the value we want for both the sent message box and the form itself.

private string MessageBoxCss { get; set; } = "oculto";
private string FormCss { get; set; } = "visible";

Now we just have to update the values when the message has been sent correctly.

private async Task Enviar()
{
    HttpClient client = ClientFactory.CreateClient("BackendApi");
    HttpResponseMessage result = await client.PostAsJsonAsync($"api/contact", _contact);
    ResultDto<ContactResponse> contactResponse = await result.Content.ReadFromJsonAsync<ResultDto<ContactResponse>>();

    if (contactResponse.Value)
    {
        MessageBoxCss = "visible";
        FormCss = "oculto";
    }
}

As we can see, once the form has been sent, only the message confirming it was sent will be visible.

backend result in blazor

 

Conclusion

In this post, we've seen how to work with forms inside Blazor as well as their validations, without the need to run JavaScript to dynamically update page elements.

Let’s not forget that forms are a basic part of our everyday professional work.

 

This post was translated from Spanish. You can see the original one here.
If there is any problem you can add a comment bellow or contact me in the website's contact form

Uso del bloqueador de anuncios adblock

Hola!

Primero de todo bienvenido a la web de NetMentor donde podrás aprender programación en C# y .NET desde un nivel de principiante hasta más avanzado.


Yo entiendo que utilices un bloqueador de anuncios como AdBlock, Ublock o el propio navegador Brave. Pero te tengo que pedir por favor que desactives el bloqueador para esta web.


Intento personalmente no poner mucha publicidad, la justa para pagar el servidor y por supuesto que no sea intrusiva; Si pese a ello piensas que es intrusiva siempre me puedes escribir por privado o por Twitter a @NetMentorTW.


Si ya lo has desactivado, por favor recarga la página.


Un saludo y muchas gracias por tu colaboración

© copyright 2025 NetMentor | Todos los derechos reservados | RSS Feed

Buy me a coffee Invitame a un café