aspnetcore/blazor/tutorials/movie-database-app/part-2.md
This article is the second part of the Blazor movie database app tutorial that teaches you the basics of building an ASP.NET Core Blazor Web App with features to manage a movie database.
In this part of the tutorial series:
:::zone pivot="vs"
In Solution Explorer, right-click the BlazorWebAppMovies project and select Add > New Folder. Name the folder Models.
Right-click the Models folder. Select Add > Class. Name the file Movie.cs. Use the following contents for the file.
:::zone-end
:::zone pivot="vsc"
Add a folder to the project named Models.
Add a class file to the Models folder named Movie.cs. Use the following contents for the file.
:::zone-end
:::zone pivot="cli"
Add a folder to the project named Models.
Add a class file to the Models folder named Movie.cs. Use the following contents for the file.
:::zone-end
Models/Movie.cs:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BlazorWebAppMovies.Models;
public class Movie
{
public int Id { get; set; }
public string? Title { get; set; }
public DateOnly ReleaseDate { get; set; }
public string? Genre { get; set; }
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
The Movie class contains:
Id), which is required by EF Core and the database to track records. In the database, the Id property is the database record's primary key.Title)ReleaseDate)Genre)Price)The question mark on a string type indicates that the property is nullable (it can hold a null value).
The EF Core database provider selects data types based on the .NET types of the model's properties. The provider also takes into account other metadata provided by xref:System.ComponentModel.DataAnnotations, which are a set of attribute classes placed above a model's property with the following format, where the {ANNOTATION} placeholder is the annotation name. You can place multiple annotations on the same line separated by commas inside the brackets, or you can place multiple annotations on separate lines, which is the approach adopted by this tutorial series.
[{ANNOTATION}]
The Price property in the Movie class file has two data annotations:
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
These annotations specify:
More information on data annotations, including adding data annotations for validation, is covered in a later part of the tutorial series.
:::zone pivot="vs"
Select Build > Build Solution from the menu bar or press <kbd>F6</kbd> on the keyboard. Confirm in the Output panel that the build succeeded.
:::zone-end
:::zone pivot="vsc"
:::moniker range=">= aspnetcore-9.0"
To add the dotnet scaffold tool, execute the following .NET CLI command in the Terminal (Terminal menu > New Terminal) opened to the project's root folder:
dotnet tool install --global Microsoft.dotnet-scaffold
:::moniker-end
:::moniker range="< aspnetcore-9.0"
To add the required NuGet packages and tools, execute the following .NET CLI commands in the Terminal (Terminal menu > New Terminal) opened to the project's root folder.
Paste all of the following commands at the prompt (>) of the Terminal. When you paste multiple commands, a warning may appear stating that multiple commands will execute. Dismiss the warning and proceed with the paste operation.
When you paste multiple commands, all of the commands execute except the last one. The last command doesn't execute until you press <kbd>Enter</kbd> on the keyboard.
dotnet tool install --global dotnet-aspnet-codegenerator
dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.AspNetCore.Components.QuickGrid
dotnet add package Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter
dotnet add package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
[!IMPORTANT] After the first eight commands execute, make sure that you press <kbd>Enter</kbd> on the keyboard to execute the last command.
[!NOTE] The preceding commands are .NET CLI commands, and .NET CLI commands are executed when entered at a PowerShell prompt, which is the default command shell of the VS Code Terminal.
The preceding commands add:
aspnet-codegenerator scaffolding tool.Microsoft.VisualStudio.Web.CodeGeneration.Design for scaffolding.Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore to use the xref:Microsoft.Extensions.DependencyInjection.DatabaseDeveloperPageExceptionFilterServiceExtensions.AddDatabaseDeveloperPageExceptionFilter%2A extension method in the Program file, which captures database-related exceptions.:::moniker-end
Save any open files.
In the Command Palette (<kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>), use the .NET: Build command to build the app.
Confirm that the app built successfully.
:::zone-end
:::zone pivot="cli"
:::moniker range=">= aspnetcore-9.0"
To add the dotnet scaffold tool, execute the following .NET CLI command in a command shell opened to the project's root folder:
dotnet tool install --global Microsoft.dotnet-scaffold
:::moniker-end
:::moniker range="< aspnetcore-9.0"
To add the required NuGet packages and tools, execute the following .NET CLI commands in a command shell opened to the project's root folder.
Paste all of the following commands at the prompt (>) of the command shell. When you paste multiple commands, a warning may appear stating that multiple commands will execute. Dismiss the warning and proceed with the paste operation.
When you paste multiple commands, all of the commands execute except the last one. The last command doesn't execute until you press <kbd>Enter</kbd> on the keyboard.
dotnet tool install --global dotnet-aspnet-codegenerator
dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.SQLite
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.AspNetCore.Components.QuickGrid
dotnet add package Microsoft.AspNetCore.Components.QuickGrid.EntityFrameworkAdapter
dotnet add package Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore
The preceding commands add:
aspnet-codegenerator scaffolding tool.Microsoft.VisualStudio.Web.CodeGeneration.Design for scaffolding.Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore to use the xref:Microsoft.Extensions.DependencyInjection.DatabaseDeveloperPageExceptionFilterServiceExtensions.AddDatabaseDeveloperPageExceptionFilter%2A extension method in the Program file, which captures database-related exceptions.:::moniker-end
Save any open files.
In a command shell opened to the project's root folder, execute the dotnet build command:
dotnet build
Confirm that the app built successfully.
:::zone-end
In this section, the Movie model is used to scaffold a database context and a UI for managing movies in the database. .NET scaffolding is a code generation framework for .NET applications. You use scaffolding to quickly add database and UI code that interacts with data models.
:::zone pivot="vs"
Right-click on the Components/Pages folder and select Add > New Scaffolded Item:
With the Add New Scaffold Item dialog open to Installed > Common > Blazor > Razor Component, select Razor Components using Entity Framework (CRUD). Select the Add button.
CRUD is an acronym for Create, Read, Update, and Delete. The scaffolder produces create, edit, delete, details, and index components for the app.
Complete the Add Razor Components using Entity Framework (CRUD) dialog:
BlazorWebAppMovies.Data.BlazorWebAppMoviesContext is generated. Use the default generated value. Select the Add button.:::zone-end
:::zone pivot="vsc"
In the Terminal (Terminal menu > New Terminal) opened to the project's root directory, execute the following command. SQLite is used as the database for users adopting VS Code tooling for this tutorial series.
:::moniker range=">= aspnetcore-9.0"
dotnet scaffold
When the initializing prompt appears, press <kbd>Enter</kbd> on the keyboard.
For the Scaffolding Category, use the arrow keys to select Blazor. Press <kbd>Enter</kbd>.
For the Command Name, use the arrow keys to select Razor Components with EntityFrameworkCore (CRUD). Press <kbd>Enter</kbd>.
CRUD is an acronym for Create, Read, Update, and Delete. The scaffolder produces create, edit, delete, details, and index components for the app.
For the .NET project file, press <kbd>Enter</kbd> to accept the app's project file (BlazorWebAppMovies.csproj).
For the Model Name, confirm that Movie (Movie class) is selected. Press <kbd>Enter</kbd>.
For the Data Context Class, type BlazorWebAppMoviesContext. Press <kbd>Enter</kbd>.
For the Database Provider, use the arrow keys to select sqlite-efcore. Press <kbd>Enter</kbd>.
For Page, confirm that CRUD is selected. Press <kbd>Enter</kbd>.
When prompted to include prerelease packages, use the arrow keys to select No. Press <kbd>Enter</kbd>.
Executing the dotnet scaffold command adds the following tools and packages to the app:
dotnet scaffold tooling.Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore to use the xref:Microsoft.Extensions.DependencyInjection.DatabaseDeveloperPageExceptionFilterServiceExtensions.AddDatabaseDeveloperPageExceptionFilter%2A extension method in the Program file, which captures database-related exceptions.:::moniker-end
:::moniker range="< aspnetcore-9.0"
dotnet aspnet-codegenerator blazor CRUD -dbProvider sqlite -dc BlazorWebAppMovies.Data.BlazorWebAppMoviesContext -m Movie -outDir Components/Pages
CRUD is an acronym for Create, Read, Update, and Delete. The blazor generator with the CRUD template produces create, edit, delete, details, and index components for the app.
The following table details the ASP.NET Core code generator options used in the preceding command:
-dbProvider: Database provider to use. Options include sqlserver (default), sqlite, cosmos, postgres.-dc: The xref:Microsoft.EntityFrameworkCore.DbContext class to use, including the namespace (BlazorWebAppMovies.Data).-m: The name of the model.-outDir: The output directory for the generated components. A folder is created from the model name in the output directory to hold the components (for example, MoviePages in this case).:::moniker-end
:::zone-end
:::zone pivot="cli"
In a command shell opened to the project's root folder, execute the following command. SQLite is used as the database for users adopting .NET CLI tooling for this tutorial series.
:::moniker range=">= aspnetcore-9.0"
dotnet scaffold
When the initializing prompt appears, press <kbd>Enter</kbd> on the keyboard.
For the Scaffolding Category, use the arrow keys to select Blazor. Press <kbd>Enter</kbd>.
For the Command Name, use the arrow keys to select Razor Components with EntityFrameworkCore (CRUD). Press <kbd>Enter</kbd>.
CRUD is an acronym for Create, Read, Update, and Delete. The scaffolder produces create, edit, delete, details, and index components for the app.
For the .NET project file, press <kbd>Enter</kbd> to accept the app's project file (BlazorWebAppMovies.csproj).
For the Model Name, confirm that Movie (Movie class) is selected. Press <kbd>Enter</kbd>.
For the Data Context Class, type BlazorWebAppMoviesContext. Press <kbd>Enter</kbd>.
For the Database Provider, use the arrow keys to select sqlite-efcore. Press <kbd>Enter</kbd>.
For Page, confirm that CRUD is selected. Press <kbd>Enter</kbd>.
When prompted to include prerelease packages, use the arrow keys to select No. Press <kbd>Enter</kbd>.
Executing the dotnet scaffold command adds the following tools and packages to the app:
dotnet scaffold tooling.Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore to use the xref:Microsoft.Extensions.DependencyInjection.DatabaseDeveloperPageExceptionFilterServiceExtensions.AddDatabaseDeveloperPageExceptionFilter%2A extension method in the Program file, which captures database-related exceptions.:::moniker-end
:::moniker range="< aspnetcore-9.0"
dotnet aspnet-codegenerator blazor CRUD -dbProvider sqlite -dc BlazorWebAppMovies.Data.BlazorWebAppMoviesContext -m Movie -outDir Components/Pages
CRUD is an acronym for Create, Read, Update, and Delete. The blazor generator with the CRUD template produces create, edit, delete, details, and index components for the app.
The following table details the ASP.NET Core code generator options used in the preceding command:
-dbProvider: Database provider to use. Options include sqlserver (default), sqlite, cosmos, postgres.-dc: The xref:Microsoft.EntityFrameworkCore.DbContext class to use, including the namespace (BlazorWebAppMovies.Data).-m: The name of the model.-outDir: The output directory for the generated components. A folder is created from the model name in the output directory to hold the components (for example, MoviePages in this case).:::moniker-end
:::zone-end
The appsettings.json file is updated with the connection string used to connect to a local database. In the following example, the {CONNECTION STRING} is the connection string automatically generated by the scaffolder:
"ConnectionStrings": {
"BlazorWebAppMoviesContext": "{CONNECTION STRING}"
}
The scaffolding process creates the following component files and movie database context class file:
Components/Pages/MoviePages
Create.razor: Creates new movie entities.Delete.razor: Deletes a movie entity.Details.razor: Shows movie entity details.Edit.razor: Updates a movie entity.Index.razor: Lists movie entities (records) in the database.Data/BlazorWebAppMoviesContext.cs: Database context file (xref:Microsoft.EntityFrameworkCore.DbContext).The component files in the MoviePages folder are described in greater detail in the next part of this tutorial. The database context is described later in this article.
:::zone pivot="vs"
If the MoviePages folder and assets aren't present after scaffolding, return to the Scaffold the model section and rescaffold the Movie model, making sure that you select the Razor Components using Entity Framework (CRUD) scaffolder under Installed > Common > Blazor > Razor Component in the Add New Scaffold Item dialog.
:::zone-end
ASP.NET Core is built with dependency injection, which is a software design pattern for achieving Inversion of Control (IoC) between classes and their dependencies. Services, such as the EF Core database context, are registered with dependency injection during application startup. These services are injected into Razor components for use by the components.
The QuickGrid component is a Razor component for efficiently displaying data in tabular form. The scaffolder places a QuickGrid component in the Index component (Components/Pages/Index.razor) to display movie entities. Calling xref:Microsoft.Extensions.DependencyInjection.EntityFrameworkAdapterServiceCollectionExtensions.AddQuickGridEntityFrameworkAdapter%2A on the service collection adds an EF Core adapter for QuickGrid to recognize EF Core-supplied xref:System.Linq.IQueryable%601 instances and to resolve database queries asynchronously for efficiency.
In combination with xref:Microsoft.AspNetCore.Builder.DeveloperExceptionPageExtensions.UseDeveloperExceptionPage%2A, xref:Microsoft.Extensions.DependencyInjection.DatabaseDeveloperPageExceptionFilterServiceExtensions.AddDatabaseDeveloperPageExceptionFilter%2A captures database-related exceptions that can be resolved by using Entity Framework migrations. When these exceptions occur, an HTML response is generated with details about possible actions to resolve the issue.
The following code is added to the Program file by the scaffolder:
builder.Services.AddDbContextFactory<BlazorWebAppMoviesContext>(options =>
options.UseSqlServer(
builder.Configuration.GetConnectionString("BlazorWebAppMoviesContext") ??
throw new InvalidOperationException(
"Connection string 'BlazorWebAppMoviesContext' not found.")));
builder.Services.AddQuickGridEntityFrameworkAdapter();
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
The migrations feature in EF Core:
EF Core adopts the code-first approach for database design and maintenance:
This is the reverse procedure of database-first approaches, where the database is designed, built, and updated first. Adopting EF Core's code-first approach aims to speed up the process of app development because most of the difficult and time-consuming database creation and management procedures are handled transparently by the EF Core tooling, so you can focus on app development.
:::zone pivot="vs"
In this section, Visual Studio Connected Services are used to issue EF Core commands that:
In Solution Explorer, double-click Connected Services. In the SQL Server Express LocalDB area of Service Dependencies, select the ellipsis (...) followed by Add migration:
Give the migration a Migration name of InitialCreate, which is a name that describes the migration. Wait for the database context to load in the DbContext class names field, which may take a few seconds. Select Finish to create the migration:
Select the Close button after the operation finishes.
Adding a migration generates code to create the initial database schema. The schema is based on the model specified in xref:Microsoft.EntityFrameworkCore.DbContext.
Select the ellipsis (...) again followed by the Update database command:
The Update database with the latest migration dialog opens. Wait for the DbContext class names field to update and for prior migrations to load, which may take a few seconds. Select the Finish button:
The update database command executes the Up method migrations that haven't been applied in a migration code file created by the scaffolder. In this case, the command executes the Up method in the Migrations/{TIME STAMP}_InitialCreate.cs file, which creates the database. The {TIME STAMP} placeholder is a time stamp.
Select the Close button after the operation finishes.
:::zone-end
:::zone pivot="vsc"
Right-click the BlazorWebAppMovies project file (BlazorWebAppMovies.csproj) and select Open in Integrated Terminal.
The Terminal window opens with a command prompt at the project directory, which contains the Program file and the app's project file (.csproj).
Execute the following .NET CLI command to add an initial migration. The migrations command generates code to create the initial database schema. The schema is based on the model specified in xref:Microsoft.EntityFrameworkCore.DbContext. The InitialCreate argument is used to name the migration. Any name can be used, but the convention is to use a name that describes the migration.
dotnet ef migrations add InitialCreate
After the preceding command completes, update the database with the update command. The update command executes the Up method on migrations that haven't been applied in a migration code file created by the scaffolder. In this case, the command executes the Up method migrations in the Migrations/{TIME STAMP}_InitialCreate.cs file, which creates the database. The {TIME STAMP} placeholder is a time stamp.
dotnet ef database update
:::zone-end
:::zone pivot="cli"
From the project's root folder, execute the following .NET CLI command to add an initial migration. The migrations command generates code to create the initial database schema. The schema is based on the model specified in xref:Microsoft.EntityFrameworkCore.DbContext. The InitialCreate argument is used to name the migration. Any name can be used, but the convention is to use a name that describes the migration.
dotnet ef migrations add InitialCreate
After the preceding command completes, update the database with the update command. The update command executes the Up method on migrations that haven't been applied in a migration code file created by the scaffolder. In this case, the command executes the Up method migrations in the Migrations/{TIME STAMP}_InitialCreate.cs file, which creates the database. The {TIME STAMP} placeholder is a time stamp.
dotnet ef database update
:::zone-end
The database context BlazorWebAppMoviesContext (Data/BlazorWebAppMoviesContext.cs):
Movie model.Movie entity set. In EF 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 xref:Microsoft.EntityFrameworkCore.DbContextOptions object. For local development, the connection string is read from the appsettings.json file.
Run the app.
Add /movies to the URL in the browser's address bar to navigate to the movies Index page.
After the Index page loads, select the :::no-loc text="Create New"::: link.
Add a movie to the database. In the following example, the classic sci-fi movie The Matrix (©1999 Warner Bros. Entertainment Inc.) is added as the first movie entry. Selecting the :::no-loc text="Create"::: button adds the movie to the database:
When you select the :::no-loc text="Create"::: button, the movie data is posted to the server and saved in the database.
:::moniker range=">= aspnetcore-9.0 < aspnetcore-10.0"
:::zone pivot="vs"
In .NET 9, the Visual Studio debugger may break with a xref:Microsoft.AspNetCore.Components.NavigationException on the line that navigates back to the Index page:
To resolve this problem:
The exception isn't thrown when a xref:Microsoft.AspNetCore.Components.NavigationManager.NavigateTo%2A method is executed throughout the rest of the tutorial series.
In .NET 10 or later:
:::zone-end
:::moniker-end
When the app returns to the Index page, the added entity appears:
Open the Edit page. Edit the movie's record and save the changes.
Examine the Delete page, but don't delete The Matrix movie from the database. The presence of this movie record is valuable in the next step of the tutorial where rendered HTML is studied and some enhancements are made to the data displayed. If you already deleted the movie, add the movie to the database again using the Create page before proceeding to the next part of the tutorial series.
:::zone pivot="vs"
Stop the app using either of the following approaches:
Use the Stop button in Visual Studio's menu bar:
Press <kbd>Shift</kbd>+<kbd>F5</kbd> on the keyboard.
:::zone-end
:::zone pivot="vsc"
Stop the app using the following approach:
:::zone-end
:::zone pivot="cli"
Stop the app using the following approach:
:::zone-end
EF Core documentation:
Startup class and methodsdotnet aspnet-codegeneratorThe Matrix is a copyright of Warner Bros. Entertainment Inc..
[!div class="step-by-step"] Previous: Create a Blazor Web App Next: Learn about Razor components