Join Jess Chadwick for an in-depth discussion in this video Using a page model to keep logic out of the view, part of ASP.NET Core: Razor Pages.
- [Instructor] Up until now, I've put all of the logic for my Razor Pages directly inside the page. However, keeping in mind everything I just described about loose coupling, this may not be the best approach when it comes to maintainability of my applications. Luckily, Razor Pages provides you with a great way to get logic out of the view and into its own separate class. This class is called a page model, and it contains all of the logic for your page, independent of the markup that's going to consume that logic.
So, let's see how to use the page model approach in our application. The next page I'm going to add to the application will be one that will allow me to add new recipes and edit existing ones. And when I'm done, it'll contain a pretty significant amount of logic, logic that I'd like to keep separate from my markup. So, that makes it a perfect candidate for the page model approach. I'm going to separate this new page from the other pages in the site by putting it its own folder named Admin, under the Pages folder.
So I'll start by creating that folder first. Then I'll use the Razor Page item template to add a new Razor Page to this new Admin folder. I'll name the new page AddEditRecipe. I can see that Visual Studio has created two files, a .cshtml file, just like I've been making manually, and a .cs file that contains a class with the name of the page, followed by the suffix, model.
The template then wires these two together, using the @model directive on line two of the page. What this directive does is dynamically adds a new property named Model that is accessible in the Razor Page and at run-time, this property will automatically be populated with a new instance of the specified model class. In this case, AddEditRecipeModel.
Now let's take a look at the class, itself. It's a simple class that inherits the Razor Pages page model base class and anything that you add to this class, will be available on that model property I just showed in the view. To demonstrate, I'll wire this page up to use routing, just like the recipe page, except I'll implement that routing in this model. I'll start by adding a property named id on the model, and then with this in place, I can switch to the markup and see that this new property is now visible off of the model object.
Then while I'm in the view, I'll add the route to the @page directive, just like I've already shown on the recipe page. And since I want to use this page to both edit an existing recipe and add new ones, I want this id to be optional. And in order to do that, I just put a question mark after the route variable name, like this. Now this page will handle URLs both with and without the id specified.
With this in place, I'll head back to the model, to actually retrieve the route value. This time however, rather than manually pulling the id value from the route values dictionary, I'll leverage another, more declarative way to get access to this value, applying the FromRoute attribute. Putting the attribute on this property is the equivalent to the line that I used to pull the id from the route values dictionary before.
In other words, look into the route values for a property named id, pull it's value, and then parse it into a number for me. Notice how I'm using a nullable long as the type for the id property. This is important since I made the id variable optional when I defined the route, which means that the id route value may or may not be populated depending on the URL the user has navigated to. When the id route value is not provided, the value of this property should be null to represent that fact.
Likewise, I could also add a nice helper property that I can check to see if I'm editing an existing recipe or creating a new one and this property will be based on whether the id property is null or not. And while I'm adding properties, I'll create a new one named Recipe that exposes the recipe we are adding or editing, which I'll use in later videos.
With these properties in place on the page model, I can now switch to the view and being referencing them. First, I'll just set the title, based on whether this is a new recipe or not. I can even display the value of the id that was passed.
When I view the page without an id in the URL, I see the title New Recipe with no id displayed. And when I view the page with an id in the URL, I see the title Edit Recipe and the value of the id that was passed. At this point, I've shown you two approaches to adding logic to your page, both with a page model and without one. So you may be wondering which one you should use at any given time.
As you create new pages in your Razor Pages applications, always stop for a moment to consider whether your page will need any kind of nontrivial logic. If the answer is yes, or if you're just not sure how complex it will be, going with the page model approach is usually the safest bet. For instance, even though, I don't have much logic in this page now, I know that I will end up with a lot of logic later, so I've chosen the page model approach right from the start.
If, however, you choose not to use the page model approach at first, and then find out that you keep adding logic to your page and it's starting to become a little more complex than you expected, it's never too late to switch to the page model approach. Just create a class that derives from the page model base class, move your logic into the new class, and then use the @model directive in your page to wire the two together and you're all set.
- Creating a new application
- Setting up pages
- Rendering dynamic content
- Reusing markup with layouts
- Increasing the maintainability of pages
- Processing data
- Validating input
- Securing an application