Getting Started With Razor Pages Using C#

There are many situations in which a budding developer will read all about how great and awesome a new technology is, and be excited to jump right into it. However, a common question crops up that has the potential to derail this embrace, and that question is: How do I get started?

And with that, where there was excitement, there are now seemingly-insurmountable obstacles. Even more discouraging, time constraints and other pressures can often push a developer to go with what might be “tried and true,” even if it is “deprecated and nearly extinct.” The goal of this article is to present a gentle introduction to Razor Pages implemented via C# and Visual Studio 2019 – Community Edition. The assumption here is that the reader already has a basic understanding of what Razor Pages are and why they may be useful.

Read: Introducing ASP.NET MVC Razor

Creating a New Project in Visual Studio

To begin, open up Visual Studio 2019 – Community Edition and on the opening dialog, choose “Create a new Project”:

C# Razor Pages

Figure 1 – Creating a New Project

This introduction will be implemented as an “ASP .NET Core Web App.” The easiest way to select this project type is to type the text into the search bar until this option appears, and then select it, and click “Next” at the bottom of the dialog:

C# Razor pages example

Figure 2 – Selecting an “ASP .NET Core Web App” Project Template

In the proud history and tradition of the use of “Hello, world!” programs to introduce a new programming concept, this project will be called “HelloRazorPage” (all one word):

Configuring razor pages

Figure 3 – HelloRazorPage Project Setup

Finally, the project will be configured to use the most current version of the .NET Framework that is installed on the computer on which Visual Studio is being run; in this case it is .NET 5.0:

Configure .NET framework

Figure 4 – .NET Framework Configuration

Upon pressing the “Create” button, the typical Visual Studio IDE screen will appear, and the following files will be prepopulated with the project. Note how each web page has a cshtml extension, along with a code-behind file, like traditional ASP.net web page development.

C# and Razor Pages

Figure 5 – Included project files, with code-behind files shown.

The best way to see how this all works together is to simply run the project as-is, without making any changes. To do this, press the “IIS Express” button in the top button bar:

Running Visual Studio Projects

Figure 6 – Running the Project

When IIS Express is run for the first time within Visual Studio, a few warnings will appear about its using self-signed SSL certificates. In order to avoid SSL certificate warnings in the development environment, indicate that the IIS Express SSL Certificate should be trusted:

IIS SSL Certificates in Visual Studio

Figure 7 – Trusting the IIS Express SSL Certificate

As a suggestion, it is advised to not click the “Don’t ask me again” checkbox, as this may suppress future warnings that may be advisable to know about. An additional warning will be generated by the computer’s default browser, which, in this case, is Microsoft Edge. Confirm that the certificate should be installed (note how this is not the default option):

Install IIS Express SSL Certificates

Figure 8 – Installing the IIS Express SSL Certificate

Upon doing all of this, the application will appear in the browser:

Razor Pages and C#

Figure 9 – Running the Application

Note how the Visual Studio IDE has changed into debugging mode. To end the IIS Express session, simply close the browser.

Read: Web Forms in ASP.NET and Razor

Using the Code-Behind File

While it would be easy to just type Hello, world as a static literal in the index.cshtml page, this wouldn’t serve much purpose in terms of an example of manipulating pages with Razor. Instead, this text will be introduced by modifying both the index.cshtml and index.cshtml.cs files. This method will be something that traditional ASP.net developers should find familiar.

Variables that reference data that is to be placed in the index.cshtml page must be declared as class members in the index.cshtml.cs code-behind file. This process is known as model binding and can be seen in the following C# code example:

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace HelloRazorPage.Pages
{
    public class IndexModel : PageModel
    {
        private readonly ILogger _logger;

        public IndexModel(ILogger logger)
        {
            _logger = logger;
        }

        public string myFirstTextLiteral;
        public void OnGet()
        {
            this.myFirstTextLiteral = "Hello, world!";
        }
    }
}

And now, the index.cshtml page must be updated to display the variable:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}
<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <h3>@Model.myFirstTextLiteral</h3>
</div>

And of course, running the code in via IISExpress gives the following result:

Razor Pages Hello World

Figure 10 – The “Hello, world!” output

Using Inline Coding in Razor Pages

Razor also supports robust, in-line coding in just the cshtml page file. The C# code example below will display the “remote” IPv6 address of the computer accessing the application, which of course is the same computer hosting it:

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}
<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
    <h3>@Model.myFirstTextLiteral</h3>
    <h4>There's no place like 
        @{
            string remoteIP = Request.HttpContext.Connection.RemoteIpAddress.ToString();
            @remoteIP
        }
    </h4>
</div>

This will produce the following output:

C# Razor Page tutorial

Figure 11 – Output of the listing above

Read: Layouts and Partial Views in Razor

Database-Driven Applications in Razor Pages and SQL Server

The following section will demonstrate a simple SQL Server tie-in for our example application. The SQL Server used in this example is a SQL Server Express installation installed on the same machine as the code. The user account in the connection string has db_owner access.

Additional Razor Pages are added just like any other item would be added to a traditional .NET project. Begin by right-clicking on the “Pages” Folder in the Solution Explorer, then select “Add” and “Razor Page”, as shown below:

Add Razor Page

Figure 12 – Adding a new Razor Page to the Project

For the purposes of this example, choose an empty Razor Page, and then click the “Add” button:

C#, Razor Pages, and Visual Studio

Figure 13 – Selecting an Empty Razor Page

The next dialog box will prompt for the filename. For this example, use Media-Manager.cshtml and then click the “Add” button:

Naming Razor Pages in C#

Figure 14 – Naming the new file

Once the name is specified, the new file and its code-behind file will be listed in the Solution Explorer:

Solution Explorer Updated

Figure 15 – The Updated Solution Explorer

Simply adding a new page to the project will not make it browsable by an end-user who does not know the name of the file. To solve this problem, it is necessary to modify the menu layout of the application so that it provides a link to the new page. To access the menu, open the Pages/Shared/_Layout.cshtml file. This can be found in the path below within the Solution Explorer:

Location of Layout.cshtml

Figure 16 – The location of _Layout.cshtml in the Solution Explorer

The changes to add another link in the top menu bar to this new file are in bold below:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>@ViewData["Title"] - HelloRazorPage</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
    <link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
    <header>
        <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
            <div class="container">
                <a class="navbar-brand" asp-area="" asp-page="/Index">HelloRazorPage</a>
                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
                        aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                </button>
                <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
                    <ul class="navbar-nav flex-grow-1">
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Media-Manager">Media Manager</a>
                        </li>
                        <li class="nav-item">
                            <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
                        </li>
                    </ul>
                </div>
            </div>
        </nav>
    </header>
    <div class="container">
        <main role="main" class="pb-3">
            @RenderBody()
        </main>
    </div>
    <footer class="border-top footer text-muted">
        <div class="container">
            &copy; 2021 - HelloRazorPage - <a asp-area="" asp-page="/Privacy">Privacy</a>
        </div>
    </footer>
    <script src="~/lib/jquery/dist/jquery.min.js"></script>
    <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
    <script src="~/js/site.js" asp-append-version="true"></script>
    @await RenderSectionAsync("Scripts", required: false)
</body>
</html>

Additionally, some CSS changes need to be added to make the sample content somewhat more presentable. This can be done by modifying the wwwroot/css/site.css file, which is located in the following section of the Solution Explorer:

site.css location

Figure 17 – Location of site.css in the Solution Explorer

table
{
    width: 100%;
}

th, td{
    padding: 10px 10px 10px 10px;
    border: 1px solid black;
}

With this change, it is now possible to link to the new page, which will be blank. Run the code using IISExpress, and then observe that not only is the Media Manager file linked, but clicking the link will show the blank page, with the menu bar on top:

Razor Pages in C# Guide

Figure 18 – The link to the new page appears in the menu bar.

Razor Pages

Figure 19 – Clicking the link shows a blank page, as expected.

Working with a Database

Now let us extend this blank page by connecting it to a simple SQL Server Express database. This code makes use of .NET’s built in SQL Server Client connectivity assemblies, but any database that is supported by .NET will work here.

Enter or paste the following code into Media-Manager.cshtml:

@page
@model HelloRazorPage.Pages.Media_ManagerModel
@using System.Data.SqlClient;
@{
    SqlConnection conn = 
        new SqlConnection("server=localhost\\SQLEXPRESS;database=RazorDemo;Trusted_Connection=True;user=RazorUser;pwd=P4$$w0rD4Me;");
    string query = "select a.artist_name, b.album_name, b.rcdid as 'album_id' from artists a, albums b where b.artist_id=a.rcdid " +
        "order by a.artist_name, b.album_name;";
}
<div class="text-center">
    <h1 class="display-4">Artists and Albums</h1>
    @{
        conn.Open();
        SqlCommand cmd = new SqlCommand(query, conn);
        SqlDataReader rdr = cmd.ExecuteReader();
        <table>
            <!-- The at-sign before the if is crucial.  The code won't be parsed otherwise and no error will be generated. -->
            <!-- And note that these are HTML Comments and not C# Comments! -->
            @if (rdr.HasRows)
            {
                <thead>
                    <tr>
                        <th>Artist</th>
                        <th>Album</th>
                    </tr>
                </thead>
                <tbody>
                    @while (rdr.Read())
                    {
                        <tr>
                            <td>@rdr["artist_name"].ToString()</td>
                            <td>@rdr["album_name"].ToString()</td>
                        </tr>
                    }
                </tbody>
            }
            else
            {
                <thead><tr><th>There are no records.</th></tr></thead>
            }
            @{
                rdr.Close();
                conn.Close();
            }
        </table>
    }
</div>

The structure of the sample database and its table are simple enough and are left as an exercise for the reader. However, the following error may appear when trying to run this code:

Missing Assembly Error Message

Figure 20 – Missing Assembly Error Message

This can be resolved by adding the Assembly System.Data.SqlClient in the NuGet Package Manager in Visual Studio.

Upon running the code, the following page content appears when clicking on the Media-Manager Page:

MS SQL Server and Razor Pages

Figure 21 – The Media Manager Page with the Sample Data

Conclusion to Razor Pages in C# Tutorial

This article presented a way to quickly get up and running with Razor Pages, starting from scratch. It didn’t take very long to go from a Hello, World! application to something which can work with a database.

One characteristic of Razor Pages that stood out in this demonstration is that unlike traditional ASP .NET code, there is far less reliance on the code-behind file. In the example here, it was completely unnecessary to even touch that file. This leads to better code organization, and it gives ASP.net a nice feature that other prominent web application languages have had for a very long time, that is, the ability to better integrate the application code with the layout and markup of the page.

This demonstration does not even show the tip of the iceberg when it comes to Razor pages. Razor technology builds upon the very solid and extensive foundation that ASP .NET has historically provided, and it can be extended into building very robust and complex web applications.

Read more C# programming tutorials.

Phil Hajjar
Phil is usually seen making things work together that shouldn’t be, but need to be. He describes himself as a marriage counselor for software and other technology systems. He appropriated this moniker way back in college as he first experimented with making disparate software work together back then, and he continues doing so in his over 20 years of professional IT experience now.

More by Author

Must Read