DEV Community

Cover image for DotVVM and ASP.NET Core: Implementing CRUD operations

DotVVM and ASP.NET Core: Implementing CRUD operations

esdanielgomez profile image Daniel Gomez Jaramillo Updated on ・8 min read

DotVVM is a ASP.NET framework that allows us to create web applications using the MVVM (Model-View-Viewmodel) design pattern with C# and HTML. In this tutorial we will learn how to create CRUD operations (Create, Read, Update, and Delete) using the DotVVM and .NET Core framework.

Want to know what are the steps to create a DotVVM app? To learn about this you can review this article: Steps to create an MVVM application (Model-View-Viewmodel) with DotVVM and ASP.NET Core

For our case study, we will take as an example entity the information of a student for the realization of CRUD operations and divide the application into three parts:

  1. Data Access Layer Implementation: to manage connection and database access.
  2. Implementation of the BL (Business Layer): for the management of services and logic of the application domain.
  3. Implementation of the application presentation layer. This section is where DotVVM comes into action.

Part 1: Data Access Layer - DAL

As the first point to create our application, in the Data Access Layer we must define the entities that the application domain will have and the DBContext at which the reference for the connection to our database will be defined.

In the application we will use the entity: Student. If we had other entities, for example: Professor, Subject, etc; these will be located in the Entities folder. For our case study, the Student entity will be defined as follows:

public class Student
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string About { get; set; }
    public DateTime EnrollmentDate { get; set; }
Enter fullscreen mode Exit fullscreen mode

On the other hand, we have the DBContext, the primary class with which our application will interact (Operations in business logic) and that will allow communication with the database:

public class StudentDbContext : DbContext
    public StudentDbContext(DbContextOptions options) : base(options)

    public DbSet<Student> Students { get; set; }
Enter fullscreen mode Exit fullscreen mode

In the StudentDbContext there are two important things to say:

  • context.Database.EnsureCreated() is a primary Entity Framework - EF method that ensures that the database exists for the context. If it exists, no action is taken. If it does not exist, the database and all its schemas are created and are also guaranteed to support the model for this context.

  • DbSet<Student> Students {get; set;}; represents a collection for the Student entity within the data model and is the gateway to database operations with this entity.

Typically this section of the DAL (entities such as Student and associations in the DbContext) is automatically generated based on entities already defined in the database through Entity Framework.

Part 2: Business Layer - BL

Now we need to define the models and create the services to control the logic of our application. In this case, what we are looking for is to have a general list of students and the specific information of each of them.


As a first point we will define our models:


public class StudentListModel
    public int Id {get; set;}
    public string FirstName {get; set;}
    public string LastName {get; set;}
Enter fullscreen mode Exit fullscreen mode


public class StudentDetailModel
    public int Id { get; set; }

    public string FirstName { get; set; }

    public string LastName { get; set; }

    public DateTime EnrollmentDate {get; set;}

    public string About { get; set; }
Enter fullscreen mode Exit fullscreen mode

And then we implement the services of our application.


In this case we have the Student service that will allow us to carry out CRUD operations.

public class StudentService
    private readonly StudentDbContext studentDbContext;

    public StudentService(StudentDbContext studentDbContext)
        this.studentDbContext = studentDbContext;

    public async Task<List<StudentListModel>> GetAllStudentsAsync()...

    public async Task<StudentDetailModel> GetStudentByIdAsync(int studentId)...

    public async Task UpdateStudentAsync(StudentDetailModel student)...

    public async Task InsertStudentAsync(StudentDetailModel student)...

    public async Task DeleteStudentAsync(int studentId)...
Enter fullscreen mode Exit fullscreen mode

For managing information stored in the database using LINQ - Language Integrated Query, a component of the Microsoft .NET platform that adds data query capabilities natively to the .NET languages. In other words, LINQ allows us to query collections of objects (the entities defined in the DAL) to handle information and perform operations on the database.

To understand a little more about how LINQ works, in the following method we can see the procedure that allows us to obtain the information of a particular student according to their identification:

public async Task<StudentDetailModel> GetStudentByIdAsync(int studentId)
    return await studentDbContext.Students.Select(
            s => new StudentDetailModel
                Id = s.Id,
                FirstName = s.FirstName,
                LastName = s.LastName,
                About = s.About,
                EnrollmentDate = s.EnrollmentDate
        .FirstOrDefaultAsync(s => s.Id == studentId);

Enter fullscreen mode Exit fullscreen mode

For more detail, see how LINQ works, you can refer to the Microsoft documentation at:

Part 3: Application Presentation Layer

Now that we have defined the DAL and BL, we must carry out the design of the website so that the user can interact with it and in this case, perform CRUD operations for the management of Students.

This is the part where DotVVM comes into action. Each page in DotVVM consists of two files:

  • A view, which is based on HTML syntax and describes how the page will look.
  • A view model, which is a class in C# that describes the state of the page (for example, values in the form fields) and controls user interactions (for example, button clicks).

For us we will have four Views and four Models associated with these Views (Viewmodels):

  • Default: will be the main page of the application where the list of registered students will be displayed.
  • Create: a page made up of a form to create new students.
  • Detail: to view a student's information in detail.
  • Edit: to modify a student's information or delete it.

Considering the Views and Viewmodels files, in Visual Studio we will see something like this:

Next, let's analyze in more detail the View and Viewmodel of Default and its components.

Default Viewmodel

public class DefaultViewModel : MasterPageViewModel
    private readonly StudentService studentService;

    public DefaultViewModel(StudentService studentService)
        this.studentService = studentService;

    public List<StudentListModel> Students { get; set; }

    public override async Task PreRender()
        Students =  await studentService.GetAllStudentsAsync();
        await base.PreRender();

Enter fullscreen mode Exit fullscreen mode

As a first point we have the StudentService instance that will allow us to access the methods to handle the operations defined in the Student service implemented in the BL.

Then we have the definition List<StudentListModel> Students of type StudentListModel defined in the model classes in the BL, which will have the list of students (Id, FirstName and LastName) to load them into a table on the main page of the web application.

A very important feature to mention is the [Bind(Direction.ServerToClient)] declaration. These types of properties allow you to specify which information is to be transferred from the server to the client or from the client to the server when using Binding Directions. Considering the case of the student list, in many cases it is not necessary to transfer the entire view model in both directions. From server to view will be fine in this case.

Learn more about Binding Directions at:

Finally in the Default Viewmodel we have the PreRender() method, which allows you to perform certain types of operations that will be performed when loading the View. In this case, a query will be made to the database by calling the service method studentService.GetAllStudentsAsync(), then the results will be assigned in the Students collection of type StudentListModel and then the page will be loaded along with the other design components.

Default View

<dot:Content ContentPlaceHolderID="MainContent">

    <div class="page-center">
        <div class="page-grid-top">
        <div class="student-image"></div>

                <dot:RouteLink Text="{resource: Texts.Label_NewStudent}" RouteName="CRUD_Create" class="page-button btn-add btn-long"/>

        <dot:GridView DataSource="{value: Students}" class="page-grid">
                <dot:GridViewTextColumn ValueBinding="{value: FirstName}" HeaderText="{resource: Texts.Label_Firstname}" />
                <dot:GridViewTextColumn ValueBinding="{value: LastName}" HeaderText="{resource: Texts.Label_Lastname}" />
                    <dot:RouteLink Text="{resource: Texts.Label_Detail}" RouteName="CRUD_Detail" Param-Id="{{value: Id}}" />
                    <dot:RouteLink Text="{resource: Texts.Label_Edit}" RouteName="CRUD_Edit" Param-Id="{{value: Id}}" />
                There are no registered students. First sign in or sign up and add some students.
Enter fullscreen mode Exit fullscreen mode

As we can see the View of Default, the layout of the page becomes in the handling of HTML and CSS statements. For our case study, there are some interesting statements and features that we can analyze:

GridView: <dot:GridView ... >, a DotVVM control that allows us to create a table or grid to display a certain list of information. In HTML we would be talking about the <table> tag. One of its attributes is DataSource: DataSource="{value: Students}", which allows you to specify the data source, in this case we refer to the list of students: Students, which was defined in the Viewmodel as we saw earlier.

In addition to grids, DotVVM also has other custom control components, for example, for TextBox, ComboBox, file handling, among others, that allow us to maintain communication between the View and the sources of information defined in the Viewmodels. See more at:

Continuing our analysis, in the GridView we have the columns FirstName and LastName of the students, but additionally, we can also add columns to perform operations on a specific record. In this case, with RouteLink, we can define a hyperlink that constructs a URL from path names and parameter values to redirect us to other pages or perform additional operations, such as viewing detail or modifying the record of a student in particular based on their ID:

<dot:RouteLink RouteName="Edit" Param-Id="{{value: Id}}" />

These paths and their corresponding parameters are to be defined in the file DotvvmStartup.cs in the ConfigureRoutes method as follows:

config.RouteTable.Add("Edit", "edit/{Id}", "Views/Edit.dothtml");

To learn more about Routing on DotVVM you can go to:

The Create, View Detail, and Modify pages follow the same logic for View and Viewmodel components. When you add some student records in the app and load the homepage with the list of them, we will have something like this:

What's next?

With these steps we have analyzed the most important parts of an MVVM web application using DotVVM y.NET Core with the help of Visual Studio 2019 to implement a CRUD about students information.

The code in this example can be found on the sample page that Visual Studio 2019 has for DotVVM when generating a new project of type: DotVVM with ASP.NET Core and selecting the option: Sample CRUD Page.

You can also find the code in this repository on GitHub here.

Thank you

In the next articles we will continue to review the components that DotVVM has for the design of web pages and case studies that may be useful to us in the future.

To be aware of these and other news, you can follow me on Twitter:

See you soon!

Discussion (0)

Editor guide