Practical .NET
Getting Started with Razor Pages: A Better Model for Web Development?
As fond as he is of using Controllers and Views, Peter isn't sure that Razor Pages aren't a better model for Web development. But the first step, adding Razor Pages to your project, isn't as easy as it should be. And, after that, you'll want to integrate them with your existing MVC application.
I like ASP.NET Core's Razor Pages because, in my mind, I think they do a better job of implementing the Single Responsibility Principle than the "standard" MVC model of Controller+View. While a Controller typically manages multiple Views and functionalities, the Razor Pages model encourages more focused models: A Razor Page is dedicated to supporting the functionality of a View. This means that Razor Pages are more focused and, as a result, easier to understand, maintain, document, test and assign to different teams.
But adopting Razor Pages isn't free: I have to give up Action methods that finish by selecting between different Views. However, to be realistic, the number of Action methods where I take advantage of choosing Views is very small. In fact, where I do want to use a different View, I'm more likely to use the RedirectToAction method than use multiple Views ... and that option is also available in Razor Pages.
The Razor Pages Model
One way to think of the Razor Page's model as collapsing into the Controller the Data Transfer Object (DTO or "model" object) that, in the "standard" MVC model is created by the Controller and passed to the View. This removes another option I have with the "standard" model: The ability to use one DTO with several different Views.
Again, this is an option that I don't often use. In fact, many developers are opposed to sharing DTOs among Views, feeling that each "model" object should be tailored to a single View (even (to the point of using different DTOs for a View's HttpGet and HttpPost methods).
This collapse does reduce the number of files in Solution Explorer by 33 percent. In fact, the number of files in Solution Explorer decreases by 66 percent because, like the old "code behind" model for Windows Forms, the file with the Razor Page's code nests underneath the View file in Solution Explorer. This means that all the components of a Razor Page are in one place rather than being spread among the Controllers, Models and Views folders.
Unlike that old "code-behind" model, though, a Razor Page's code model is divorced from its View and, like a Controller, can be tested completely independently of its View.
Adding Razor Pages: Annoyances
In my experience, however, adding your first Razor Page to a project isn't as easy as it should be: Razor Pages must be kept in a Pages folder in your site, and the initial mechanism for adding Pages won't create that folder for you. You'll need to right-click on your project in Solution Explorer, select Add Folder and, when the Add Folder dialog is displayed, add a Folder called Pages.
Once that Pages folder is created, you can right-click on it and select Add | New Item to display the Add New Item dialog. On the left side of that dialog, you'll need to ensure that the ASP.NET Core option is selected to get the list of ASP.NET Core item templates. From that list, select Razor Page, give your page a name and click the Add button.
You'll now find that you have two files: a cshtml file (your View) and a cshtml.cs file (your Controller/DTO file). The name of the class in that cshtml.cs file will be name of your Razor Page with "Model" tacked on at the end (your class must also inherit from the PageModel class).
For a Razor Page called Customer, then, the code file will look like this:
namespace CustomerManagement.Pages
{
public class CustomerModel : PageModel
You'll find that your View file begins like this:
@page
@model CustomerModel
The page directive is required. The model directive should refer to the class but, for the first Razor Page you add, there won't be a namespace directive and the compiler won't be able to find the related class. So, you'll need to modify your View to reference the code file's namespace:
@page
@using CustomerManagement.Pages
@model CustomerModel
More changes are required if, for example, you want to use a layout View with your Page.
Again, in my experience, these annoyances go away as you add your subsequent Razor Pages. Once you've added that first Razor Page to a project's Pages folder, the next time you right-click on the Pages folder, you'll find a new Add Page choice in the pop-up menu. That choice brings up an Add Scaffolding dialog, which lists nothing but Razor Page templates.
With that dialog, after you select the template you want and click the Add button, you'll get an Add Razor Page dialog. This dialog gives you several checkoff options for creating your Page, including whether you want a separate code file, use a Layout page or create your Razor Page as partial page. The View file will then be added with all the directives you need for it to, you know, work.
Integrating Razor Pages
With a Razor Page in place, I can integrate that Page with an Action method by using the RedirectToPage method in a Controller. This code in an Action would send the user to a CustomerManagement Page in my project's Pages folder:
return RedirectToPage("/CustomerManagement");
Similar code in the Page's code file allows me to redirect users to other Pages in the project.
I can also integrate Pages both with other Pages and Action methods. Methods in Razor Pages follow the Web API standard of tying methods to HTTP verbs: Method names in Pages have names like OnGet/OnGetAsync, OnPost/OnPostAsync and so on. So, a typical method in a Page's code file to redirect to the user to another page would look like this:
public IActionResult OnPost()
{
return this.RedirectToPage("/FirstPage");
}
If, on the other hand, I wanted to send the user to an Action method in a Controller, I would use this code in my Razor Page method:
public IActionResult OnPost()
{
return this.RedirectToAction("Index", "Home");
}
Of course, all this leaves open how you actually use a Razor Page. I'll return to that later this month.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.