Web application development is unquestionably successful when using the Model-View-Controller (MVC) design. Many IT groups adopted the approach, which was included in frameworks including Ruby on Rails, Django, and Spring. Microsoft made the MVC pattern available to developers on April 2, 2009, with the introduction of ASP.NET MVC. The strategy primarily favors ceremonial over configuration and focuses largely on the notions of convention over configuration. For less complex applications, the ceremony may include an overhead that is optional.
ASP.NET developers were exposed to Razor Pages, a novel method for creating online apps, with the release of.NET Core 2.0. Despite having some similarities to WebForms, the framework has learned over a decade of designing web frameworks. With the capacity to utilize many of the same features available in ASP.NET MVC, Razor Pages demonstrates the thinking that went into developing it.
In this article, we’ll take a look at an existing ASP.NET MVC application, start the transition to Razor Pages, and examine any areas where Razor Pages might not be the best choice. In previous post, we have also written tutorial about how to migrate Asp.net core 3 to Asp.net core 5, feel free to read the article if you want to plan to upgrade your Asp.net core version.
Reason Use Razor Pages
By acknowledging the limitations of an HTML form and the typical use cases that come with developing line-of-business apps, Razor Pages accepts the traditional web. This is not to argue that the possibilities for Razor Pages are limited by these restrictions. Razor Pages, on the other hand, can typically accomplish everything an ASP.NET MVC application can.
Routing, Model Binding, ModelState, Validation, Razor views, and ActionResult return types are among the features shared by ASP.NET MVC and Razor Pages, which are built on top of ASP.NET Core. The available HTTP semantics of Razor Pages are where we observe the most notable changes.
The whole range of HTTP methods (GET, POST, DELETE, etc.) are supported by ASP.NET MVC, whereas Razor Pages only allow GET, POST, and PUT.
ASP.NET MVC and WebAPI have historically supported HTTP-based APIs, and ASP.NET Core’s implementation of MVC has placed a strong emphasis on the pattern as a means of creating APIs for single-page apps. The fact that they are the same methods enabled by HTML’s form tag explains the constraint.
Model, View, and Controller are ASP.NET MVC’s three primary divisions, as we’ll see later in this essay. Razor Pages adopts a completely different strategy by combining all three components into what is essentially one project component. A PageModel is used by Razor Pages to describe the actions and conditions of each endpoint. The cognitive load and context switching between the model, view, and controller folders can be lessened with fewer project components. Less code for a given value is always advantageous.
ASP.NET MVC Structure
The MVC pattern contains three main components, as was already mentioned. Take note of the MVC elements in the solution explorer as we examine our sample project.
We have the following elements:
- Controllers
- Models/ViewModels
- Views
We wish to use ViewModels for our mutation-based endpoints as a best practice. To show how all the pieces go together, let’s dissect one of the actions in our WidgetsController
.
[HttpPost, Route("create")] public IActionResult Create([FromForm] EditModel request) { if (ModelState.IsValid) { // widget service service.Add(request.Name); return RedirectToAction("Index"); } return View("New", request); }
The characteristics of HttpPost
and Route
should be the first things we pay attention to. The characteristics aid in directing an HTTP request to our controller action in ASP.NET MVC. In order to connect the values from the request’s form to our C# instance, we additionally make use of a request model. Next, we use ModelState
to check the legitimacy of our HTTP request. We then either save the data or give the user a new view. We examined each of the key elements of the MVC pattern in one single operation.
For a total of six endpoints, we must write an additional five actions in order to create the sample used in this post. The approaches are same for all endpoints. You can run the project from GitHub to examine the finished implementation or look at it in the solution explorer.
Razor Pages Structure
The collapsible programming model is Razor Pages’ main advantage. By checking at the Razor Pages folders in the solution explorer, we can see that. We are down to one folder when our domain models, which house our services, are excluded.
Let’s migrate the Create
MVC action from the previous section to the Razor Pages philosophy.
public class Create : PageModel { [BindProperty, Required] public string Name { get; set; } // public void OnGet() { } public IActionResult OnPost([FromServices]WidgetService service) { if (ModelState.IsValid) { var widget = service.Add(Name); return RedirectToPage("Index"); } return Page(); } }
- The routing of our page is conventional. It uses the content path of our page to build the route.
- The GET method is implicit since the Razor Page handles both GET and POST requests. We do not need it in our
PageModel
, because we have no logic on GET requests. - The
Create
class is the ViewModel. We bind theName
property on each POST request. We don’t need any other objects. - We are using
ModelState
for validation, just like MVC. - We are using
IActionResult
to route our client, just like MVC.
We should also be aware of the connection between our views and page models within the same folder. We can see how we reference the “Create” PageModel by looking at our view.
@page @model RazorPagesMigration.Pages.Widgets.Create <h2>Create</h2> <form method="post" asp-page="Create"> <label asp-for="Name"></label> <input asp-for="Name" /> <span asp-validation-for="Name"></span> <button type="submit">Save Widget</button> </form>
The only differences between the two, as shown in our MVC view implementation, are the references to the asp-page
properties on the HTML form.
In our Edit
page, we can see a more sophisticated example of a Razor Page implementation.
public class Edit : PageModel { private readonly WidgetService service; public Edit(WidgetService service) { this.service = service; } [BindProperty(SupportsGet = true)] public int Id { get; set; } [BindProperty, Required] public string Name { get; set; } public IActionResult OnGet() { var widget = service.Get(Id); if (widget == null) return NotFound(); Name = widget.Name; return Page(); } public IActionResult OnPost() { if (ModelState.IsValid) { service.Update(Id, Name); return RedirectToPage("Index"); } return Page(); } }
@page
directive that describes the anticipated route parameters. Our client must supply an identification in the URI path on the Edit page.@page "{id:int}" @model RazorPagesMigration.Pages.Widgets.Edit <h2>Edit</h2> <form method="post" asp-page="edit" asp-route-id="@Model.Id"> <label asp-for="Name"></label> <input asp-for="Name" /> <span asp-validation-for="Name"></span> <button type="submit">Save Widget</button> </form>
Great Combination Razor Pages and MVC
It is obvious from looking at the example project that Razor Pages and MVC are built on the same framework. Razor Pages’ request pipeline is remarkably similar to MVC’s, using elements like validation, action results, razor views, and more. We replicate the layout of our MVC views in our example. We now come to a crucial realization: MVC and Razor Pages are not incompatible. They work well together as a team. We can move different components of our applications gradually and precisely thanks to the same codebase.
Why You Shouldn’t Use Razor Pages
As was already established, a Razor Page has very limited support for HTTP methods. It’s challenging to develop APIs on this platform because it doesn’t support all HTTP methods completely. We would gain more from continuing with ASP.NET MVC if our frontend only uses frontend model binding and JavaScript. Although it is not impossible, doing so would be painful.
While deciding between MVC and Razor Pages, our user interface complexity may be a factor. Our decision to adopt Razor Pages is influenced by the fundamental UI component. PageModel is the building block used by Razor Pages, however MVC allows us to design smaller components. An full online application might display a sign-up form for a newsletter, as an illustration. Requests for newsletter signup might be handled better via an MVC endpoint.
Also, Razor Pages’ built-in conventional routing architecture is extremely constrained. If we desire deeply nested route pathways, our solution structure can become extremely complex. Although there are ways to solve this issue utilizing Razor Pages norms, most people should avoid altering the accepted practices.
Final Verdict
Because of their same base, Razor Pages and ASP.NET MVC work extremely well together when used in a single project. The majority of developers should use both in their applications and can. Also, we should think about the MVC infrastructure that already exists and whether switching some components of our applications to Razor Pages makes sense. HTML-focused pages are excellent candidates for a Razor Pages rewrite, and as this post’s examples demonstrate, we can reuse many of the same MVC parts.
Those who are creating frontends or API backends with a lot of JavaScript should keep using the MVC pattern since it gives them the most flexibility with regard to HTTP methods, routing, and response processing.
The decision between Razor Pages and MVC is ultimately subjective, and as this post has demonstrated, they both use a lot of the same infrastructure. We can see from the sample project that we’ve been given that, regardless of the direction we go, feature parity is achievable. Any current ASP.NET developers should give the Razor Pages approach some thought since it significantly reduces the formality associated with using the MVC paradigm.
I definitely suggest LearnRazorPages.com as a top-notch resource for new and seasoned developers that are interested in learning more about Razor Pages.
If you’re looking to host your ASP.NET MVC website, you can go with ASPHostPortal. Get your ASP.NET hosting as low as $1.00/month with ASPHostPortal. Our fully featured hosting already includes
- Easy setup
- 24/7/365 technical support
- Top level speed and security
- Super cache server performance to increase your website speed
- Top 9 data centers across the world that you can choose.
Yury Sobolev is Full Stack Software Developer by passion and profession working on Microsoft ASP.NET Core. Also he has hands-on experience on working with Angular, Backbone, React, ASP.NET Core Web API, Restful Web Services, WCF, SQL Server.