Part 4 of tutorial series on Razor Pages

By Rick Anderson and Joe Audette

View or download sample code (how to download).

The RazorPagesMovieContext object handles the task of connecting to the database and mapping Movie objects to database records. The database context is registered with the Dependency Injection container in the ConfigureServices method in Startup.cs:

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

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

The ASP.NET Core Configuration system reads the ConnectionString key. For local development, configuration gets the connection string from the appsettings.json file.

The generated connection string will be similar to the following:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-bc;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

When the app is deployed to a test or production server, an environment variable can be used to set the connection string to a test or production database server. For more information, see Configuration.

SQL Server Express LocalDB

LocalDB is a lightweight version of the SQL Server Express database engine that's targeted for program development. LocalDB starts on demand and runs in user mode, so there's no complex configuration. By default, LocalDB database creates *.mdf files in the C:\Users\<user>\ directory.

  1. From the View menu, open SQL Server Object Explorer (SSOX).

    View menu

  2. Right-click on the Movie table and select View Designer:

    Contextual menus open on Movie table

    Movie tables open in Designer

    Note the key icon next to ID. By default, EF creates a property named ID for the primary key.

  3. Right-click on the Movie table and select View Data:

    Movie table open showing table data

Seed the database

Create a new class named SeedData in the Models folder with the following code:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesMovie.Data;
using System;
using System.Linq;

namespace RazorPagesMovie.Models
{
    public static class SeedData
    {
        public static void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new RazorPagesMovieContext(
                serviceProvider.GetRequiredService<
                    DbContextOptions<RazorPagesMovieContext>>()))
            {
                // Look for any movies.
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
}

If there are any movies in the database, the seed initializer returns and no movies are added.

if (context.Movie.Any())
{
    return;
}

Add the seed initializer

Replace the contents of the Program.cs with the following code:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RazorPagesMovie.Models;
using System;

namespace RazorPagesMovie
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    SeedData.Initialize(services);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }

            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

In the previous code, the Main method has been modified to do the following:

  • Get a database context instance from the dependency injection container.
  • Call the seedData.Initialize method, passing to it the database context instance.
  • Dispose the context when the seed method completes. The using statement ensures the context is disposed.

The following exception occurs when Update-Database has not been run:

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

Test the app

  1. Delete all the records in the database. Use the delete links in the browser or from SSOX

  2. Force the app to initialize by calling the methods in the Startup class, so the seed method runs. To force initialization, IIS Express must be stopped and restarted. Stop and restart IIS with any of the following approaches:

    1. Right-click the IIS Express system tray icon in the notification area and select Exit or Stop Site:

      IIS Express system tray icon

      Contextual menu

    2. If the app is running in non-debug mode, press F5 to run in debug mode.

    3. If the app in debug mode, stop the debugger and press F5.

The app shows the seeded data:

Movie application open in browser showing movie data

Additional resources

View or download sample code (how to download).

The RazorPagesMovieContext object handles the task of connecting to the database and mapping Movie objects to database records. The database context is registered with the Dependency Injection container in the ConfigureServices method in Startup.cs:

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

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

The ASP.NET Core Configuration system reads the ConnectionString key. For local development, configuration gets the connection string from the appsettings.json file.

The generated connection string will be similar to the following:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-bc;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

When the app is deployed to a test or production server, an environment variable can be used to set the connection string to a test or production database server. See Configuration for more information.

SQL Server Express LocalDB

LocalDB is a lightweight version of the SQL Server Express database engine that's targeted for program development. LocalDB starts on demand and runs in user mode, so there's no complex configuration. By default, LocalDB database creates *.mdf files in the C:\Users\<user>\ directory.

  • From the View menu, open SQL Server Object Explorer (SSOX).

    View menu

  • Right-click on the Movie table and select View Designer:

    Contextual menus open on Movie table

    Movie tables open in Designer

Note the key icon next to ID. By default, EF creates a property named ID for the primary key.

  • Right-click on the Movie table and select View Data:

    Movie table open showing table data

Seed the database

Create a new class named SeedData in the Models folder with the following code:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using RazorPagesMovie.Data;
using System;
using System.Linq;

namespace RazorPagesMovie.Models
{
    public static class SeedData
    {
        public static void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new RazorPagesMovieContext(
                serviceProvider.GetRequiredService<
                    DbContextOptions<RazorPagesMovieContext>>()))
            {
                // Look for any movies.
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
}

If there are any movies in the database, the seed initializer returns and no movies are added.

if (context.Movie.Any())
{
    return;
}

Add the seed initializer

Replace the contents of the Program.cs with the following code:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RazorPagesMovie.Models;
using System;

namespace RazorPagesMovie
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    SeedData.Initialize(services);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }
            
            host.Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }
}

In the previous code, the Main method has been modified to do the following:

  • Get a database context instance from the dependency injection container.
  • Call the seedData.Initialize method, passing to it the database context instance.
  • Dispose the context when the seed method completes. The using statement ensures the context is disposed.

The following exception occurs when Update-Database has not been run:

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

Test the app

  • Delete all the records in the database. Use the delete links in the browser or from SSOX.

  • Force the app to initialize by calling the methods in the Startup class, so the seed method runs. To force initialization, IIS Express must be stopped and restarted. Stop and restart IIS with any of the following approaches:

    • Right-click the IIS Express system tray icon in the notification area and tap Exit or Stop Site:

      IIS Express system tray icon

      Contextual menu

      • If the app is running in non-debug mode, press F5 to run in debug mode.
      • If the app in debug mode, stop the debugger and press F5.

The app shows the seeded data:

Movie application open in Chrome showing movie data

Additional resources

View or download sample code (how to download).

The RazorPagesMovieContext object handles the task of connecting to the database and mapping Movie objects to database records. The database context is registered with the Dependency Injection container in the ConfigureServices method in Startup.cs:

// 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")));
}

For more information on the methods used in ConfigureServices, see:

The ASP.NET Core Configuration system reads the ConnectionString key. For local development, configuration gets the connection string from the appsettings.json file.

The generated connection string will be similar to the following:

{
  "Logging": {
    "LogLevel": {
      "Default": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "RazorPagesMovieContext": "Server=(localdb)\\mssqllocaldb;Database=RazorPagesMovieContext-1234;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

When the app is deployed to a test or production server, an environment variable can be used to set the connection string to a test or production database server. See Configuration for more information.

SQL Server Express LocalDB

LocalDB is a lightweight version of the SQL Server Express database engine that's targeted for program development. LocalDB starts on demand and runs in user mode, so there's no complex configuration. By default, LocalDB database creates *.mdf files in the C:/Users/<user/> directory.

  • From the View menu, open SQL Server Object Explorer (SSOX).

    View menu

  • Right-click on the Movie table and select View Designer:

    Contextual menu open on Movie table

    Movie table open in Designer

Note the key icon next to ID. By default, EF creates a property named ID for the primary key.

  • Right-click on the Movie table and select View Data:

    Movie table open showing table data

Seed the database

Create a new class named SeedData in the Models folder with the following code:

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;

namespace RazorPagesMovie.Models
{
    public static class SeedData
    {
        public static void Initialize(IServiceProvider serviceProvider)
        {
            using (var context = new RazorPagesMovieContext(
                serviceProvider.GetRequiredService<
                    DbContextOptions<RazorPagesMovieContext>>()))
            {
                // Look for any movies.
                if (context.Movie.Any())
                {
                    return;   // DB has been seeded
                }

                context.Movie.AddRange(
                    new Movie
                    {
                        Title = "When Harry Met Sally",
                        ReleaseDate = DateTime.Parse("1989-2-12"),
                        Genre = "Romantic Comedy",
                        Price = 7.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters ",
                        ReleaseDate = DateTime.Parse("1984-3-13"),
                        Genre = "Comedy",
                        Price = 8.99M
                    },

                    new Movie
                    {
                        Title = "Ghostbusters 2",
                        ReleaseDate = DateTime.Parse("1986-2-23"),
                        Genre = "Comedy",
                        Price = 9.99M
                    },

                    new Movie
                    {
                        Title = "Rio Bravo",
                        ReleaseDate = DateTime.Parse("1959-4-15"),
                        Genre = "Western",
                        Price = 3.99M
                    }
                );
                context.SaveChanges();
            }
        }
    }
}

If there are any movies in the database, the seed initializer returns and no movies are added.

if (context.Movie.Any())
{
    return;
}

Add the seed initializer

Replace the contents of the Program.cs with the following code:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using RazorPagesMovie.Models;
using System;
using Microsoft.EntityFrameworkCore;

namespace RazorPagesMovie
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var host = CreateWebHostBuilder(args).Build();

            using (var scope = host.Services.CreateScope())
            {
                var services = scope.ServiceProvider;

                try
                {
                    var context=services.
                        GetRequiredService<RazorPagesMovieContext>();
                    context.Database.Migrate();
                    SeedData.Initialize(services);
                }
                catch (Exception ex)
                {
                    var logger = services.GetRequiredService<ILogger<Program>>();
                    logger.LogError(ex, "An error occurred seeding the DB.");
                }
            }

            host.Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>();
    }
}

In the previous code, the Main method has been modified to do the following:

  • Get a database context instance from the dependency injection container.
  • Call the seedData.Initialize method, passing to it the database context instance.
  • Dispose the context when the seed method completes. The using statement ensures the context is disposed.

A production app would not call Database.Migrate. It's added to the preceding code to prevent the following exception when Update-Database has not been run:

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

Test the app

  • Delete all the records in the database. You can do this with the delete links in the browser or from SSOX

  • Force the app to initialize by calling the methods in the Startup class, so the seed method runs. To force initialization, IIS Express must be stopped and restarted. You can do this with any of the following approaches:

    • Right-click the IIS Express system tray icon in the notification area and tap Exit or Stop Site:

      IIS Express system tray icon

      Contextual menu

      • If the app is running in non-debug mode, press F5 to run in debug mode.
      • If the app in debug mode, stop the debugger and press F5.

The app shows the seeded data:

Movie application open in Chrome showing movie data

The next tutorial will clean up the presentation of the data.

Additional resources