OdeToCode IC Logo

.NET Core Opinion 14 - Razor Pages for HTML, Controllers for APIs

Thursday, September 12, 2019

.NET Core opinions are returning from a summer holiday in time to brave the melancholia of autumn.

ASP.NET Core 2.0 introduced Razor Pages, which I believe are superior to the MVC framework when building HTML applications with .NET Core.

Razor Pages encourage a separation of concerns in presentation layer logic, just as the MVC framework does. Razor pages also follow patterns like dependency injection that promote flexibility and testability. But, Razor Pages also offer clear advantages over MVC when generating HTML and processing forms on the server.

Pages Bring Focus

Razor Pages encourage developers to remain constrained in the number of features they add to a class. With pages, you typically pick a specific feature to implement using only GET and POST methods, while controllers can grow to implement dozens of different actions.

Pages versus Controllers

It was easy to see the overstuffed controller phenomenon when using the ASP.NET Identity framework. The Razor Pages version of ASP.NET Identity (shown below on the left) makes it easy to find specific features because the pages are granular. The controller version uses only two controllers with dozens of assorted actions inside. It’s worth noting that the ASP.NET Identity project now supports only Razor Pages when scaffolding a UI.

Imagine trying to find the functionality to change a password in the application. With Razor Pages it is easy to spot the page, while the controller approach hides the feature inside a mega-controller with views and models scattered across other directories.

Pages Organize Features

Speaking of feature organization, I’ve always been a fan of feature folders with the MVC framework. The MVC design pattern wants us to separate concerns using controllers, views, and models. But, nothing in the MVC framework says the models, views, and controllers need to be physically separated into distinct files and spread across separate directories. One of the more frustrating aspects of working with MVC, other than HTML helpers, was trying to track down all the files I need to open when working on a specific feature.

Razor pages maintain a separation of concerns without spraying code across the file system. The page code functions like a controller while the page view contains the presentation logic. You’ll find the code file and the view file nested together. Models and view models can live anywhere but are typically exposed as direct properties of the page, so all the pieces are easy to find.

public class DetailModel : PageModel
{
    private readonly LeagueData leagueData;

    public int SwanCount = 59;
    public Season Season { get; set; } = new Season();

    public DetailModel(LeagueData leagueData)
    {
        this.leagueData = leagueData;
    }

    public void OnGet(int id)
    {
        var query = new SeasonDetailQuery(id);
        Season = leagueData.Execute(query);
    }
}

Pages Build Better URLs

Anecdotal evidence tells me that applications built with Razor pages have better URL structures than apps with controllers. Controller apps tend to overuse the default routing template, which leads to a flat URL structure and lots of controller actions taking an ID parameter. Razor pages, on the other hand, tend to promote the organization of related pages into subfolders. Given that ASP.NET Core derives a page URL from the page’s physical location, the URLs are hierarchical and better describe the different features and regions of an application. It’s also easy to look at the UI, and find the Razor page responsible for a particular screen.

What Are Razor Pages Missing?

Razor pages have a lot to offer, including features I haven’t detailed yet, like automatic anti-forgery token validation.

There are also features that do not exist in Razor pages, despite what the ill-informed say.

There is no viewstate in Razor pages. There are also no synthetic initialize or click events. A Razor page is no more stateful than a controller with it’s ModelState data structure. In short, Razor Pages aren’t related to Web Forms or Web Matrix Web Pages. Razor pages are an authentic abstraction for programming the web.

Summary

Razor Pages are a welcomed refinement to the MVC framework and include many optimizations for sever-side HTML generation and form processing. Try them out before rushing to judgment!

The need to use the MVC framework is fading into the background with ASP.NET Core. Instead of MVC, we have Razor Pages for HTML apps, Controllers for 'REST' APIs, gRPC services for coupled APIs, and SignalR for real time communications.


Comments
Gravatar Krisztian Gyuris Friday, September 13, 2019
Great article! Ths is the first article that helps me to understand why I might want to use Razor pages instead of MVC Controllers. They do not explain the advantages of this feature on microsoft.com.
Gravatar Allen Newton Friday, September 13, 2019
I agree, great post. Razor Pages is far superior in terms of organization alone to MVC. It is also possible to split your Razor Pages out into separate projects so that you can keep much if not all of your UI code separate from your service layer and backend code. I'm somewhat surprised that the Microsoft community is not talking about Razor Pages much more. Shiny new thing syndrome, I guess.
Gravatar Howard Richards Monday, September 16, 2019
I agree totally Scott - I've come from ASP.NET WebForms to MVC and now to Razor Pages (and Blazor). MVC was a very logically structured system but a nightmare to navigate - a controller, a model, a view, and API controller and probably some JavaScript, all in totally separate folders spread around the application.
Ponant Friday, September 20, 2019
Scott thank you very much for this thought. Another missing feature of Razor Pages is that it does not allow you to build strongly typed routes. For large applications that is problematic. Best
Gravatar Mohamoud Wednesday, September 25, 2019
Its amazing how Scott is always able to say so much in so little words !!! I really LOVE how you focus on the most IMPORTANT features of Pages, which is: "...Razor Pages encourage developers to remain constrained in the number of features they add to a class....With pages, you typically pick a specific feature to implement using only GET and POST methods, while controllers can grow to implement dozens of different actions." I think thats the KILLER feature of Razor Pages and I am liking it too.
Your Comment