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”:
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:
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):
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:
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.
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:
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:
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):
Figure 8 – Installing the IIS Express SSL Certificate
Upon doing all of this, the application will appear in the browser:
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:
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:
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:
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:
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:
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:
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:
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"> © 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:
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:
Figure 18 – The link to the new page appears in the menu bar.
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:
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:
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.