Developers just starting their ASP.NET web development journey might have heard the term Razor, and had developers apply it within many different situations. We’ll explore the beginnings of Razor, what it aims to accomplish, the frameworks it is currently in use with, and open-source (OSS) use cases for Razor developers are using today.
An Introduction To Razor
Razor is a markup syntax that flows seamlessly between Hypertext Markup Language (HTML) and C# and Visual Basic syntax, with C# being the most commonly used. When looking at an ASP.NET solution, Razor files will have extensions of .cshtml
, .vbhtml
, or .razor
. The compiled artifact of Razor is executable code that writes HTML to the HTTP response. The compilation of Razor provides improved performance in production scenarios.
First released in January 2011, Microsoft designed Razor to simplify the creation of views within the ASP.NET MVC 3 framework and is the successor to the aspx
syntax found in traditional ASP.NET WebForms applications. The goal of Razor syntax is to produce server-side rendered HTML artifacts for web clients.
The syntax of Razor is recognizable through multiple reserved symbols and keywords that allow developers to transition into the scope of C# and back out to HTML, the most prominent being the @
symbol. Let’s take a look at a brief snippet of Razor syntax.
<span>@DateTime.Now</span>
.NET developers will notice the use of the DateTime
class to render the current time to the output. DateTime
within the C# scope while the <span>
tag is in HTML. There are more C# constructs useable within Razor, such as if/else
blocks, switch
statements, looping constructs, comments, and more. Developers can find a detailed listing of Razor syntax at the official Microsoft Documentation site.
The driving philosophy behind Razor is to bring ASP.NET developers closer into the web ecosystem by leveraging existing syntax and technologies. The traditional aspx
format put ASP.NET developers at a disadvantage and made it difficult to leverage the HTML community’s advancements. The closer ASP.NET developers are to HTML, the more they can lean on other professionals, ecosystems, and technologies to deliver web-based solutions. Rather than be an opaque abstraction, Razor embraces HTML, CSS, and JavaScript as a necessity when building web applications.
The Razor syntax continues to evolve and has seen additional enhancements. While built on top of a foundation of C# syntax, .NET continues to add reserved keywords to improve the developer experience. Some of these keywords are specific to the context in which developers are using Razor.
ASP.NET Core MVC and the RazorViewEngine
As mentioned in the previous section, Razor’s intended use case was for the ASP.NET MVC framework, primarily powering the View parts that developers would be building. While ASP.NET MVC can support different view engines, the default is the RazorViewEngine
found under the Microsoft.AspNetCore.Mvc.Razor
namespace.
ASP.NET Core MVC Razor views are a superset of Razor, providing developers with more functionality when constructing views. This added functionality comes from the RazorPage
type under the Microsoft.AspNetCore.Mvc.Razor
namespace, which adds several contextual properties and methods not native to vanilla Razor. Some properties include:
- HttpContext
- Model
- ViewData
- Section helper methods
ASP.NET Core developers will likely never see the RazorViewEngine
directly registered in their ASP.NET applications because ASP.NET registers the component with calls to AddControllersWithViews
, which in turn invokes AddRazorViewEngine()
.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
}
ASP.NET Core MVC will resolve views based on the registered view engines and their internal conventions. All developers need to understand the view locating rules, which I’ve written about in a previous blog post, which I highly recommend reading.
We can invoke the View
method from a controller, finding and executing our view definition.
public IActionResult Index()
{
return View();
}
Since our controller is the HomeController
and action the Privacy
action, we need a correlating Privacy
view.
@{
ViewData["Title"] = "Privacy Policy";
}
<h1>@ViewData["Title"]</h1>
<p>Use this page to detail your site's privacy policy.</p>
In this small Razor sample, we can see uses of code blocks, setting an MVC-specific property of ViewData
with an indexed value, and inline access of the same value.
The MVC usage of Razor is likely the syntax and patterns developers will be most familiar with as it’s been around the .NET community the longest. It is critical to note that many of the constructs are MVC specific, and that can be confusing for some when trying to understand where Razor the syntax starts and where ASP.NET Core MVC the framework begins.
Razor Pages
Razor Pages is a highly-opinionated approach to building web applications, leaning heavily on the lessons learned from years of developing with the MVC framework. Razor Pages drops the ceremony of controllers and takes a more page-focused mindset.
Razor Pages is a great starting point for folks starting their ASP.NET journey, as it distills the required parts needed to build an interactive web experience. Adopters of Razor Pages will interact with concepts like rendering HTML, model binding, and request/response handling.
Razor pages have much of the same syntax as ASP.NET MVC Razor views, with few exceptions. Let’s take a look at a Razor page implementation.
@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>
</div>
The essential difference is the presence of the @page
directive, which tells ASP.NET Core to treat the Razor view as a combination of MVC action and view. The presence of the directive allows the page to handle incoming requests directly. The @model
directive is similar to the Model found in MVC with one difference: the defined model type must inherit from PageModel
found in the Microsoft.AspNetCore Mvc.RazorPages
namespace.
Apart from the infrastructural differences, the Razor syntax used in ASP.NET Core MVC and Razor Pages is identical. Many MVC-style applications can be ported to Razor Pages with little modification to the views, apart from link generation, which now uses references to pages rather than controllers and actions.
Blazor
Blazor is another technology within the ASP.NET Core family that relies on Razor syntax. Blazor is a framework for building interactive client-side experiences powered by Razor, SignalR, and minimal JavaScript. Blazor focuses on the .NET developers’ experience, translating C# logic which many Razor users are familiar with, into dynamic user experiences.
When building Blazor experiences, there are two fundamental building blocks developers will consider, each ending with a .razor
extension:
- Blazor Pages
- Razor Components
The low-level building blocks of Blazor are components, which are self-contained and reusable elements that we can compose within a page. Let’s take a look at a Blazor page.
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?"/>
We can see the @page
directive again, similar to the usage under the Razor Pages programming model. The directive makes the Razor page accessible via a route, in this case, the current site’s root path.
We may also notice the use of a Razor component named SurveyPrompt
. Let’s look at this component’s implementation.
<div class="alert alert-secondary mt-4" role="alert">
<span class="oi oi-pencil mr-2" aria-hidden="true"></span>
<strong>@Title</strong>
<span class="text-nowrap">
Please take our
<a target="_blank" class="font-weight-bold" href="https://go.microsoft.com/fwlink/?linkid=2137813">brief survey</a>
</span>
and tell us what you think.
</div>
@code {
[Parameter]
public string Title { get; set; }
}
The Razor syntax within the component is where Blazor and previously mentioned approaches start to differ. We can see HTML is still an essential part of Blazor, but the @code
directive is now where we can add properties, methods, and general logic to our Blazor pages.
From our Blazor components, we can execute both client-side interactive code and make asynchronous server calls to run server-side dependencies. Blazor determines what code executes on the client and what runs on the server. In general, code modifying HTML elements will run on the client, while code that accesses server dependencies will run on the server, with the results being marshaled back to the client via SignalR.
Except for some additional razor keywords like @code
, Razor syntax in Blazor should be familiar to developers. Underscoring the philosophy of Blazor, writing client-side rich experiences should be intuitive for developers coming from MVC or Razor Pages applications.
Open-Source Libraries
We’ve seen that ASP.NET Core, while very similar, has three different permutations of Razor: ASP.NET Core MVC, Razor Pages, and Blazor. These technologies have a solid foundation of Razor and share much of the same syntax. They differ in their choice of base classes, which allows each approach to augment the API it offers developers adopting the technology.
The adaptability and enjoyable experience that Razor offers open-source developers have made it a popular choice for authors looking to use C# to generate XML-based outputs, HTML being one of the more popular artifacts.
Other Razor use cases include, but are not limited to:
- Email generation
- Static Site generators
- Generating PDFs
- Third-party Web Frameworks
- Templating
Searching for the term Razor on NuGet.org produces over 1,024 packages.
Again, while Razor is reuseable by the OSS community, each framework’s particulars are tied to the inner-workings of ASP.NET Core. In short, OSS authors might need to rebuild elements to bring a similar API surface to developers.
Conclusion
Razor syntax is a foundational specification that merges HTML and C#/VB into an enjoyable developer experience. Razor brings ASP.NET developers closer to the pillars that make web development fun and exciting: HTML, CSS, and JavaScript. Doing so also helps bring other professionals and external communities into the orbit of ASP.NET development without sacrificing years of hard-earned expertise.
ASP.NET Core MVC and Razor Pages help developers build server-side experiences, while Blazor brings Razor development to client-side experiences. With the OSS community’s help, Razor also finds practical uses in generating artifacts like PDFs, emails, and static websites.