`) generates the label caption and for attribute for the Title property.
The [Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-2.1) (`
`) uses the DataAnnotations attributes and produces HTML attributes needed for jQuery Validation on the client-side.
# 4. Work with SQL Server LocalDB
The MovieContext 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 the Startup.cs file
See services.AddDbContext`
`(options =>
options.UseSqlServer(Configuration.GetConnectionString("RazorPagesMovieContext")));
For more information on the methods used in ConfigureServices, see:
EU General Data Protection Regulation ([GDPR](https://docs.microsoft.com/en-us/aspnet/core/security/gdpr?view=aspnetcore-2.1)) support in ASP.NET Core for CookiePolicyOptions.
[SetCompatibilityVersion](https://docs.microsoft.com/en-us/aspnet/core/mvc/compatibility-version?view=aspnetcore-2.1)
The ASP.NET Core [Configuration](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-2.1) system reads the ConnectionString. For local development, it gets the connection string from the appsettings.json file. The name value for the database (Database={Database name}) will be different for your generated code. The name value is arbitrary.
When you deploy the app to a test or production server, you can use an environment variable or another approach to set the connection string to a real SQL Server. See [Configuration](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/index?view=aspnetcore-2.1) 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/`` directory**.
From the View menu, open SQL Server Object Explorer (SSOX).
Right click on the Movie table and select **View 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**
### Seed the database
Create a new **class named SeedData in the Models folder**. Replace the generated code with the following: ...
If there are any movies in the DB, the seed initializer returns and no movies are added.
### Add the seed initializer
In Program.cs, modify the Main method to do the following:
- Get a DB context instance from the dependency injection container.
- Call the seed method, passing to it the context.
- Dispose the context when the seed method completes.
The following code shows the **updated Program.cs file...**
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 https://localhost:44374/Movies
- Delete all the records in the DB. You can do this with the delete links in the browser or from SSOX
- Force the app to initialize (call 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
- If you were running VS in non-debug mode, press F5 to run in debug mode.
- If you were running VS in debug mode, stop the debugger and press F5.
The app shows the seeded data: **works ok**
# 5. Update pages (data presentation - view)
1. We don't want to see the time (12:00:00 AM in movies list)
2. ReleaseDate should be Release Date (two words)
Change in Models/Movie.cs :
```
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace RazorPagesMovie.Models
{
public class Movie
{
public int ID { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
```
Right click on [DataType(DataType.Date)] - a red squiggly line > Quick Actions and Refactorings.
Select using System.ComponentModel.DataAnnotations;
Visual Studio **adds at script top using System.ComponentModel.DataAnnotations;**
Right click on [Column(TypeName = "decimal(18, 2)")] - a red squiggly line > Quick Actions and Refactorings on the [Column] atribute
and select **using System.ComponentModel.DataAnnotations.Schema;**
The [Column(TypeName = "decimal(18, 2)")] data annotation is required so Entity Framework Core can correctly map Price to currency in the database. For more information, see [Data Types](https://docs.microsoft.com/ef/core/modeling/relational/data-types).
We'll cover [DataAnnotations](https://docs.microsoft.com/en-us/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-6) in the next chapter. The [Display](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.metadata.displaymetadata) attribute specifies what to display for the name of a field (in this case "Release Date" instead of "ReleaseDate"). The [DataType](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.dataannotations.internal.datatypeattributeadapter) attribute specifies the type of the data (Date), so the time information stored in the field isn't displayed.
https://localhost:44374/Movies - Browse to Pages/Movies and hover over an Edit link to see the target URL.
The Edit, Details, and Delete links are generated by the [Anchor Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-2.1) in the Pages/Movies/Index.cshtml file.
Tag Helpers enable server-side code to participate in creating and rendering HTML elements in Razor files. In the preceding code, the AnchorTagHelper dynamically generates the HTML href attribute value from the Razor Page (the route is relative), the asp-page, and the route id (asp-route-id). See URL generation for Pages for more information.
Use View Source from your favorite browser to examine the generated markup. A portion of the generated HTML is shown below:
```
Edit |
Details |
Delete
|
```
The dynamically-generated links pass the movie ID with a query string (for example, http://localhost:5000/Movies/Details?id=2).
Update the Edit, Details, and Delete Razor Pages to use the "{id:int}" route template. Change the page directive for each of these pages from @page to @page "{id:int}". Run the app and then view source. The generated HTML adds the ID to the path portion of the URL:
HTML
```
Edit |
Details |
Delete
|
```
A request to the page with the "{id:int}" route template that does not include the integer will return an HTTP 404 (not found) error. For example, http://localhost:5000/Movies/Details will return a 404 error. To make the ID optional, append ? to the route constraint:
@page "{id:int?}"
Posting and binding review
Examine the Pages/Movies/Edit.cshtml.cs file:
```
public class EditModel : PageModel
{
private readonly RazorPagesMovieContext _context;
public EditModel(RazorPagesMovieContext context)
{
_context = context;
}
[BindProperty]
public Movie Movie { get; set; }
public async Task OnGetAsync(int? id)
{
if (id == null)
{
return NotFound();
}
Movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
if (Movie == null)
{
return NotFound();
}
return Page();
}
public async Task OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Attach(Movie).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!_context.Movie.Any(e => e.ID == Movie.ID))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
}
```
When an HTTP GET request is made to the Movies/Edit page (for example, http://localhost:5000/Movies/Edit/2):
The OnGetAsync method fetches the movie from the database and returns the Page method.
The Page method renders the Pages/Movies/Edit.cshtml Razor Page. The Pages/Movies/Edit.cshtml file contains the model directive (@model RazorPagesMovie.Pages.Movies.EditModel), which makes the movie model available on the page.
The Edit form is displayed with the values from the movie.
When the Movies/Edit page is posted:
The form values on the page are bound to the Movie property. The [BindProperty] attribute enables Model binding.
C#
[BindProperty]
public Movie Movie { get; set; }
If there are errors in the model state (for example, ReleaseDate cannot be converted to a date), the form is posted again with the submitted values.
If there are no model errors, the movie is saved.
The HTTP GET methods in the Index, Create, and Delete Razor pages follow a similar pattern. The HTTP POST OnPostAsync method in the Create Razor Page follows a similar pattern to the OnPostAsync method in the Edit Razor Page.
# 6. Search
# 7. New field
# 8. Validation