Add a model to a Razor Pages app in ASP.NET Core

By Rick Anderson

In this section, classes are added for managing movies in a cross-platform SQLite database. Apps created from an ASP.NET Core template use a SQLite database. The app's model classes are used with Entity Framework Core (EF Core) (SQLite EF Core Database Provider) to work with the database. EF Core is an object-relational mapping (ORM) framework that simplifies data access.

The model classes are known as POCO classes (from "plain-old CLR objects") because they don't have any dependency on EF Core. They define the properties of the data that are stored in the database.

Add a data model

Right-click the RazorPagesMovie project > Add > New Folder. Name the folder Models.

Right click the Models folder. Select Add > Class. Name the class Movie.

Add the following properties to the Movie class:

using System;
using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

The Movie class contains:

  • The ID field is required by the database for the primary key.

  • [DataType(DataType.Date)]: The DataType attribute specifies the type of the data (Date). With this attribute:

    • The user is not required to enter time information in the date field.
    • Only the date is displayed, not time information.

DataAnnotations are covered in a later tutorial.

Build the project to verify there are no compilation errors.

Scaffold the movie model

In this section, the movie model is scaffolded. That is, the scaffolding tool produces pages for Create, Read, Update, and Delete (CRUD) operations for the movie model.

Create a Pages/Movies folder:

  • Right click on the Pages folder > Add > New Folder.
  • Name the folder Movies

Right click on the Pages/Movies folder > Add > New Scaffolded Item.

Image from the previous instructions.

In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > Add.

Image from the previous instructions.

Complete the Add Razor Pages using Entity Framework (CRUD) dialog:

  • In the Model class drop down, select Movie (RazorPagesMovie.Models).
  • In the Data context class row, select the + (plus) sign and change the generated name from RazorPagesMovie.Models.RazorPagesMovieContext to RazorPagesMovie.Data.RazorPagesMovieContext. This change is not required. It creates the database context class with the correct namespace.
  • Select Add.

Image from the previous instructions.

The appsettings.json file is updated with the connection string used to connect to a local database.

Files created

The scaffold process creates and updates the following files:

  • Pages/Movies: Create, Delete, Details, Edit, and Index.
  • Data/RazorPagesMovieContext.cs

Updated

  • Startup.cs

The created and updated files are explained in the next section.

Initial migration

In this section, the Package Manager Console (PMC) is used to:

  • Add an initial migration.
  • Update the database with the initial migration.

From the Tools menu, select NuGet Package Manager > Package Manager Console.

PMC menu

In the PMC, enter the following commands:

Add-Migration InitialCreate
Update-Database

The preceding commands generate the following warning: "No type was specified for the decimal column 'Price' on entity type 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'."

You can ignore that warning, it will be fixed in a later tutorial.

The migrations command generates code to create the initial database schema. The schema is based on the model specified in DbContext. The InitialCreate argument is used to name the migrations. Any name can be used, but by convention a name is selected that describes the migration.

The update command runs the Up method in migrations that have not been applied. In this case, update runs the Up method in Migrations/<time-stamp>_InitialCreate.cs file, which creates the database.

Examine the context registered with dependency injection

ASP.NET Core is built with dependency injection. Services (such as the EF Core DB context) are registered with dependency injection during application startup. Components that require these services (such as Razor Pages) are provided these services via constructor parameters. The constructor code that gets a DB context instance is shown later in the tutorial.

The scaffolding tool automatically created a DB context and registered it with the dependency injection container.

Examine the Startup.ConfigureServices method. The highlighted line was added by the scaffolder:

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddDbContext<RazorPagesMovieContext>(options =>
      options.UseSqlServer(Configuration.GetConnectionString("RazorPagesMovieContext")));
}

The RazorPagesMovieContext coordinates EF Core functionality (Create, Read, Update, Delete, etc.) for the Movie model. The data context (RazorPagesMovieContext) is derived from Microsoft.EntityFrameworkCore.DbContext. The data context specifies which entities are included in the data model.

using Microsoft.EntityFrameworkCore;

namespace RazorPagesMovie.Models
{
    public class RazorPagesMovieContext : DbContext
    {
        public RazorPagesMovieContext (DbContextOptions<RazorPagesMovieContext> options)
            : base(options)
        {
        }

        public DbSet<RazorPagesMovie.Models.Movie> Movie { get; set; }
    }
}

The preceding code creates a DbSet<Movie> property for the entity set. In Entity Framework terminology, an entity set typically corresponds to a database table. An entity corresponds to a row in the table.

The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

Test the app

  • Run the app and append /Movies to the URL in the browser (http://localhost:port/movies).

If you get the error:

SqlException: Cannot open database "RazorPagesMovieContext-GUID" requested by the login. The login failed.
Login failed for user 'User-name'.

You missed the migrations step.

  • Test the Create link.

    Create page

    Note

    You may not be able to enter decimal commas in the Price field. To support jQuery validation for non-English locales that use a comma (",") for a decimal point and for non US-English date formats, the app must be globalized. For globalization instructions, see this GitHub issue.

  • Test the Edit, Details, and Delete links.

The next tutorial explains the files created by scaffolding.

Additional resources

In this section, classes are added for managing movies in a cross-platform SQLite database. Apps created from an ASP.NET Core template use a SQLite database. The app's model classes are used with Entity Framework Core (EF Core) (SQLite EF Core Database Provider) to work with the database. EF Core is an object-relational mapping (ORM) framework that simplifies data access.

The model classes are known as POCO classes (from "plain-old CLR objects") because they don't have any dependency on EF Core. They define the properties of the data that are stored in the database.

Add a data model

Right-click the RazorPagesMovie project > Add > New Folder. Name the folder Models.

Right click the Models folder. Select Add > Class. Name the class Movie.

Add the following properties to the Movie class:

using System;
using System.ComponentModel.DataAnnotations;

namespace RazorPagesMovie.Models
{
    public class Movie
    {
        public int ID { get; set; }
        public string Title { get; set; }

        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }
        public string Genre { get; set; }
        public decimal Price { get; set; }
    }
}

The Movie class contains:

  • The ID field is required by the database for the primary key.

  • [DataType(DataType.Date)]: The DataType attribute specifies the type of the data (Date). With this attribute:

    • The user is not required to enter time information in the date field.
    • Only the date is displayed, not time information.

DataAnnotations are covered in a later tutorial.

Build the project to verify there are no compilation errors.

Scaffold the movie model

In this section, the movie model is scaffolded. That is, the scaffolding tool produces pages for Create, Read, Update, and Delete (CRUD) operations for the movie model.

Create a Pages/Movies folder:

  • Right click on the Pages folder > Add > New Folder.
  • Name the folder Movies

Right click on the Pages/Movies folder > Add > New Scaffolded Item.

Image from the previous instructions.

In the Add Scaffold dialog, select Razor Pages using Entity Framework (CRUD) > Add.

Image from the previous instructions.

Complete the Add Razor Pages using Entity Framework (CRUD) dialog:

  • In the Model class drop down, select Movie (RazorPagesMovie.Models).
  • In the Data context class row, select the + (plus) sign and accept the generated name RazorPagesMovie.Models.RazorPagesMovieContext.
  • Select Add.

Image from the previous instructions.

The appsettings.json file is updated with the connection string used to connect to a local database.

The scaffold process creates and updates the following files:

Files created

  • Pages/Movies: Create, Delete, Details, Edit, and Index.
  • Data/RazorPagesMovieContext.cs

File updated

  • Startup.cs

The created and updated files are explained in the next section.

Initial migration

In this section, the Package Manager Console (PMC) is used to:

  • Add an initial migration.
  • Update the database with the initial migration.

From the Tools menu, select NuGet Package Manager > Package Manager Console.

PMC menu

In the PMC, enter the following commands:

Add-Migration Initial
Update-Database

The Add-Migration command generates code to create the initial database schema. The schema is based on the model specified in the DbContext (In the RazorPagesMovieContext.cs file). The InitialCreate argument is used to name the migration. Any name can be used, but by convention a name that describes the migration is used. For more information, see Tutorial: Using the migrations feature - ASP.NET MVC with EF Core.

The Update-Database command runs the Up method in the Migrations/<time-stamp>_InitialCreate.cs file. The Up method creates the database.

Note

The preceding commands generate the following warning: "No type was specified for the decimal column 'Price' on entity type 'Movie'. This will cause values to be silently truncated if they do not fit in the default precision and scale. Explicitly specify the SQL server column type that can accommodate all the values using 'HasColumnType()'." You can ignore that warning, it will be fixed in a later tutorial.

Examine the context registered with dependency injection

ASP.NET Core is built with dependency injection. Services (such as the EF Core DB context) are registered with dependency injection during application startup. Components that require these services (such as Razor Pages) are provided these services via constructor parameters. The constructor code that gets a DB context instance is shown later in the tutorial.

The scaffolding tool automatically created a DB context and registered it with the dependency injection container.

Examine the Startup.ConfigureServices method. The highlighted line was added by the scaffolder:

// This method gets called by the runtime. 
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is 
        // needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    services.AddDbContext<RazorPagesMovieContext>(options =>
      options.UseSqlServer(
          Configuration.GetConnectionString("RazorPagesMovieContext")));
}

The RazorPagesMovieContext coordinates EF Core functionality (Create, Read, Update, Delete, etc.) for the Movie model. The data context (RazorPagesMovieContext) is derived from Microsoft.EntityFrameworkCore.DbContext. The data context specifies which entities are included in the data model.

using Microsoft.EntityFrameworkCore;

namespace RazorPagesMovie.Models
{
    public class RazorPagesMovieContext : DbContext
    {
        public RazorPagesMovieContext (DbContextOptions<RazorPagesMovieContext> options)
            : base(options)
        {
        }

        public DbSet<RazorPagesMovie.Models.Movie> Movie { get; set; }
    }
}

The preceding code creates a DbSet<Movie> property for the entity set. In Entity Framework terminology, an entity set typically corresponds to a database table. An entity corresponds to a row in the table.

The name of the connection string is passed in to the context by calling a method on a DbContextOptions object. For local development, the ASP.NET Core configuration system reads the connection string from the appsettings.json file.

Test the app

  • Run the app and append /Movies to the URL in the browser (http://localhost:port/movies).

If you get the error:

SqlException: Cannot open database "RazorPagesMovieContext-GUID" requested by the login. The login failed.
Login failed for user 'User-name'.

You missed the migrations step.

  • Test the Create link.

    Create page

    Note

    You may not be able to enter decimal commas in the Price field. To support jQuery validation for non-English locales that use a comma (",") for a decimal point and for non US-English date formats, the app must be globalized. For globalization instructions, see this GitHub issue.

  • Test the Edit, Details, and Delete links.

The next tutorial explains the files created by scaffolding.

Additional resources