ASP.NET, CMS, UI Development

Razor Pages in ASP.NET Core

What is ASP.NET Core?

ASP.NET Core is an open source and cloud-optimized web framework for developing modern web applications that can be developed and run on different platforms irrespective of the underlying architecture like Windows, Linux and the Mac. It includes the MVC framework, which now combines the features of MVC and Web API into a single web programming framework.

  • ASP.NET Core apps can run on .NET Core or on the full .NET Framework.
  • It was architect to provide an optimized development framework for apps that are deployed to the cloud or run on-premises.
  • It consists of modular components with minimal overhead, so that flexibility can be retained while constructing the solutions.
  • ASP.NET Core apps can be developed and run cross-platform on Windows, Mac and Linux.
  • ASP.NET Core 2 allows making asynchronous Web API by using async await keyword

 

What are Razor Pages?

ASP.NET Core Razor Pages is a page controller framework for building dynamic, data-driven web sites in-order to have clean separation of concerns and a better layer of abstraction and create page-oriented solution design. Based on the latest version of ASP.NET from Microsoft – ASP.NET Core, Razor Pages supports cross platform development and can be deployed to different Operating systems like Windows, Unix and Mac operating systems.

The Razor Pages framework is lightweight and very flexible. It provides the developer with full control over rendered HTML. The framework is built on top of ASP.NET Core MVC, and is enabled by default when MVC is enabled in a .NET Core application. Razor Pages is the recommended framework for cross platform server-side HTML generation on .NET Core. Working with Razor Pages does not put a pre-requisite of having knowledge or experience in MVC on the developer.

Razor Pages makes use of the popular C# programming language for server-side programming, and the easy-to-learn Razor templating syntax for embedding C# in HTML mark-up to generate content for browsers dynamically.

 

Why Razor Pages?

Razor Pages is suitable for all kinds of developers from beginners to enterprise level. It is based on a page-centric development model, offering a familiarity to web developers with experience of other page-centric frameworks such as PHP, Classic ASP, Java Server Pages, ASP.NET Web Pages and ASP.NET Web Forms. It is also relatively easy for the beginner to learn, and it includes all of the advanced features of ASP.NET Core making it just as suitable for large, scalable, team-based projects. Razor page approach also reduces the complexity of the project solution by discarding the unnecessary nuts and bolts at different places, where each page will have its own logic file to deal with, without having to interact with a common controller file. Being page centric, each page has got a separate abstractive file to handle the communication with the data set.

 

Razor Pages in Action

We will be creating a simple CRUD application called ‘RazorPagesPOC’ to demonstrate the use of Razor Pages in ASP.NET Core. Every front-end file will have an extension ‘.cshtml’ and there will be corresponding logic file under its hierarchy having an extension ‘.cshtml.cs’.

 

 

Let’s start by creating a Project in Visual Studio 2017 called ‘RazorPagesPOC’

 

Create a Model ‘Employee.cs’ which has the following properties. We will use this model to hold the values during the CRUD operation.  We  will be including Model level annotations like [Required] and [DisplayName] to add required constraint, custom validation message  and a different display name from the property name. 

The application we will be creating will allow us to add Employees from ‘Employee.cshtml’ Razor page, edit employee from ‘EditEmployee.cshtml’ Razor page and view and delete employees from ‘AllEmployee.cshtml’.

All these Razor Pages can be created by right-clicking on the ‘Pages’ folder in solution explorer > Go to ‘Add’ option > Click on ‘New Item’> A dialog will appear like below. Click on ‘Razor Page’ and give it a name, for example, ‘Employee.cshtml’.

 

Similarly, we will be adding two more Razor pages called ‘EditEmployee.cshtml’ and ‘AllEmployee.cshtml’. Each .cshtml file will be having its own logic file with extension ‘.cshtml.cs’.

For CRUD operation to take place, we will be using SQL server management studio to create a database with which our application would be interacting.

We will be creating a Database called ‘EmployeeDB’ in which we will be creating table called ‘EmployeeTB’ which would be storing the data for every employee.

First thing for saving data in Database we need an ORM we are going to use ‘Entity framework core’.

To install the package, just right click on the project  and then select Manage NuGet package. The below dialog of NuGet Package Manager will pop up.

In the browse tab, type ‘Microsoft.EntityFrameworkCore.SqlServer’ in the search box and just click on Install button.

After adding a reference, now add a connection string in appsetting.json file. 

Next, we are going to add a new Service in Startup.cs class for injecting dependency.

Now we will be adding a class called DatabaseContext in Models folder which would act as a medium to interact with the db through entity framework.

After adding a DatabaseContext class, next, we are going to inherit DbContext class.

After inheriting with DbContext, next we are creating a constructor which takes DbContextOptions as an input parameter and also inherits the base class constructor (: base(options)) [DbContext]. Whenever we use DatabaseContext class, DbContext instance will be injected there.

The following code snippet represents DatabaseContext .cs class

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace RazorPagesPOC.Models
{
    public class DatabaseContext : DbContext
    {
        public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
        {

        }

        public DbSet<Employee> EmployeeTB { get; set; }
    }
}

Now as everything is set up, let us give a UI structure to the first page of the application ‘Employee.cshtml’. The purpose of the page would be to add an employee to the db. Below is the Html code for the same.

@page
@model EmployeeModel
@using RazorPagesPOC.Models


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


<div class="limiter">
    <div class="container-login100" style="background-image: url('images/bg-01.jpg');">
        <div class="wrap-login100">
            <form method="post" class="login100-form validate-form">
                

                <span class="login100-form-title p-b-34 p-t-27" style="margin-bottom: 20px;">
                    Add Employee Form
                </span>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.EmployeeName" class="input100 no-left-padding" placeholder="Name" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.EmployeeName"></span>

                </div>


                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.Address" class="input100 no-left-padding" placeholder="Address" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.Address"></span>

                </div>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.City" class="input100 no-left-padding" placeholder="City" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.City"></span>

                </div>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.Country" class="input100 no-left-padding" placeholder="Country" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.Country"></span>

                </div>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.PhoneNumber" class="input100 no-left-padding" placeholder="Phone Number" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.PhoneNumber"></span>

                </div>


                <div class="container-login100-form-btn">
                    <button type="submit" class="login100-form-btn">
                        Save
                    </button>
                </div>


            </form>
            </div>
        </div>
</div>

The logic file of the ‘Employee.cshtml’ would be ‘Employee.cshtml.cs’ and this class would be handling the Get and Post requests. The code in the class would be 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesPOC.Models;

namespace RazorPagesPOC.Pages
{
    public class EmployeeModel : PageModel
    {


        DatabaseContext _Context;

        public EmployeeModel(DatabaseContext databaseContext)
        {
            _Context = databaseContext;
        }

        [BindProperty]
        public Employee Employee  { get; set; }

        public void OnGet()
        {
           
        }

        public IActionResult OnPost()
        {
            var employee = Employee;
            if(!ModelState.IsValid)
            {
                return Page();
            }
            var result = _Context.Add(employee);
            _Context.SaveChanges();
            
            return RedirectToPage("AllEmployee");
        }

    }
}

Now lets understand this code. Once we run the application and navigate to localhost:8080/Employee (For example, Port Number is 8080). The OnGet() handler would be called and according to the code snippet, it will simply  render the .cshtml on the browser.

Once the fields are filled and save button is clicked, the values in the field would be binded to the Employee variable of type ‘Employee’. The binding would be possible because of [BindProperty] annotation.

The submit event will call the OnPost() handler and using the object of the DatabaseContext class, the data will be saved. The following screen shots explain the functionality.

The data will be saved in the db table, the following screenshot validates that 

 

Once the data is saved, the user is navigated to the ‘AllEmployee’ screen. The UI and code behind the page is given in the code snipet.

AllEmployee.cshtml

@page
@model AllEmployeeModel
@{
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


<div class="limiter">
    <div class="container-login100" style="background-image: url('images/bg-01.jpg');">
        <div class="wrap-login100" style="width:auto;">
            <table class="table" style="color:white;">
                <thead>
                    <tr>
                        <th>
                            @Html.DisplayName("Name")
                        </th>
                        <th>
                            @Html.DisplayName("Address")
                        </th>
                        <th>
                            @Html.DisplayName("Country")
                        </th>
                        <th>
                            @Html.DisplayName("City")
                        </th>
                        <th>
                            @Html.DisplayName("Phone Number")
                        </th>
                        <th>Edit | Delete</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var item in Model.EmployeeList)
                    {
                        <tr>
                            <td>
                                @Html.DisplayFor(modelItem => item.EmployeeName)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Address)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.Country)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.City)
                            </td>
                            <td>
                                @Html.DisplayFor(modelItem => item.PhoneNumber)
                            </td>
                            <td>
                                <a style="text-decoration:none;color:white;" href="./EditEmployee/@item.EmployeeId"> Edit</a> |
                                
                                <a style="text-decoration:none;color:white;" asp-page="./AllEmployee" onclick="return confirm('Are you sure you want to delete this item?');"
                                   asp-page-handler="Delete" asp-route-id="@item.EmployeeId">Delete</a>
                            </td>
                        </tr>
                    }
                </tbody>
                
            </table>
            <div class="container-login100-form-btn btn-wrapper">
                <button id="addNew" class="login100-form-btn add-button-style">
                    Add New
                </button>
            </div>
        </div>

    </div>
</div>

<script>
    $("#addNew").click(function () {
        window.location = "/Employee";

    });
</script>

AllEmployee.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesPOC.Models;

namespace RazorPagesPOC.Pages
{
    public class AllEmployeeModel : PageModel
    {
        DatabaseContext _Context;
        public AllEmployeeModel(DatabaseContext databasecontext)
        {
            _Context = databasecontext;
        }

        public List<Employee> EmployeeList { get; set; }

        public void OnGet()
        {
            var data = (from employeelist in _Context.EmployeeTB
                        select employeelist).ToList();

            EmployeeList = data;
        }

        public ActionResult OnGetDelete(int? id)
        {
            if (id != null)
            {
                var data = (from employee in _Context.EmployeeTB
                            where employee.EmployeeId == id
                            select employee).SingleOrDefault();

                _Context.Remove(data);
                _Context.SaveChanges();
            }
            return RedirectToPage("AllEmployee");
        }
    }
}

This page will display all the employees added from the Employee page. The page will have controls to edit or delete the employee record from the DB. The OnGet() method returns the list of employees from the db which is then iterated over in the Razor page in a table tag to create dynamic rows of records.

The OnGetDelete(id) is the method which triggers the delete operation. Whenever the ‘Delete’ link is clicked, the corresponding employee’s id is passed to OnGetDelete method which retrieves the data record from the list and removes it from the db table and saves the changes and then again loads the ‘AllEmployee’ page. An alert is shown to the user for the confirmation of delete operation.

 

Once the user clicks on the edit link, the user will be navigated to ‘EditEmployee’ page.

 The code snippet (both UI and Code) is as follows 

EditEmployee.cshtml

@page "{id:int}"
@model EditEmployeeModel
@using RazorPagesPOC.Models


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

<style>
    .no-left-padding {
        padding-left: 0px;
    }

    .color-yellow {
        color: yellow
    }
</style>
<div class="limiter">
    <div class="container-login100" style="background-image: url('/images/bg-01.jpg');">
        <div class="wrap-login100">
            <form method="post" class="login100-form validate-form">
                <input asp-for="Employee.EmployeeId" type="hidden" />

                <span class="login100-form-title p-b-34 p-t-27" style="margin-bottom: 20px;">
                    Edit Employee Form
                </span>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.EmployeeName" class="input100 no-left-padding" placeholder="Name" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.EmployeeName"></span>

                </div>


                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.Address" class="input100 no-left-padding" placeholder="Address" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.Address"></span>

                </div>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.City" class="input100 no-left-padding" placeholder="City" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.City"></span>

                </div>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.Country" class="input100 no-left-padding" placeholder="Country" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.Country"></span>

                </div>

                <div class="wrap-input100 validate-input">
                    <input asp-for="Employee.PhoneNumber" class="input100 no-left-padding" placeholder="Phone Number" />
                    <span class="focus-input100"></span>
                    <span class="color-yellow" asp-validation-for="Employee.PhoneNumber"></span>

                </div>


                <div class="container-login100-form-btn">
                    <button type="submit" class="login100-form-btn">
                        Update
                    </button>
                </div>


            </form>
        </div>
    </div>
</div>

EditEmployee.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPagesPOC.Models;

namespace RazorPagesPOC.Pages
{
    public class EditEmployeeModel : PageModel
    {
        DatabaseContext _Context;
        public EditEmployeeModel(DatabaseContext databasecontext)
        {
            _Context = databasecontext;
        }


        [BindProperty]
        public Employee Employee { get; set; }

        public void OnGet(int? id)
        {
            if (id != null)
            {
                var data = (from employee in _Context.EmployeeTB
                            where employee.EmployeeId == id
                            select employee).SingleOrDefault();

                Employee = data;
            }
        }

        public ActionResult OnPost()
        {
            var employee = Employee;
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _Context.Entry(employee).Property(x => x.EmployeeName).IsModified = true;
            _Context.Entry(employee).Property(x => x.PhoneNumber).IsModified = true;
            _Context.Entry(employee).Property(x => x.Address).IsModified = true;
            _Context.Entry(employee).Property(x => x.City).IsModified = true;
            _Context.Entry(employee).Property(x => x.Country).IsModified = true;
            _Context.SaveChanges();
            return RedirectToPage("AllEmployee");
        }
    }
}

As we can see from the code snippet, OnGet() method expects Employee Id and then it fetches the corresponding employee from the db using DatabaseContext class and then returns the Employee object to the Razor Page.

In this page,  we are going to show record and allow the user to edit details and update it.

The first thing here to see is @page”{id: int}” directive, which tells that page need “{id: int}”int id  (EmployeeID) then only it will accept requests else it will returns an HTTP 404 (not found) error.

Note : @page”{id: int}” it is kind of routing in Razor pages.

Once the update event completes its execution, the user is redirected to ‘AllEmployee’ screen to see the updated employee records. 

Finally, we have learned, about Razor Pages and along with that how to do CRUD operations with Razor Pages in a step by step way. The functionality can be extended to other complex operations with different pages having independent logic file. 

About The Author

Leave a Reply

*