replace viewData with strong types (#4924)

* replace viewData with strong types

* work

* work
pull/4925/head
Rick Anderson 2017-12-04 18:25:56 -10:00 committed by GitHub
parent b155aeda42
commit 152469f1ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 74 additions and 58 deletions

View File

@ -198,7 +198,9 @@ In a web app, the `DbContext` that reads an entity and displays the data is disp
## Update the Delete page
In this section, code is added to implement a custom error message when the call to `SaveChanges` fails.
In this section, code is added to implement a custom error message when the call to `SaveChanges` fails. Add a string to contain possile error messages:
[!code-csharp[Main](intro/samples/cu/Pages/Students/Delete.cshtml.cs?name=snippet1&highlight=12)]
Replace the `OnGetAsync` method with the following code:

View File

@ -14,7 +14,7 @@
<form sp-page="./Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
Find by name: <input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-page="./Index">Back to full List</a>
</p>
@ -25,8 +25,8 @@
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["NameSort"]"
asp-route-currentFilter="@ViewData["CurrentFilter"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
</th>
@ -34,8 +34,8 @@
@Html.DisplayNameFor(model => model.Student[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["DateSort"]"
asp-route-currentFilter="@ViewData["CurrentFilter"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].EnrollmentDate)
</a>
</th>
@ -71,16 +71,16 @@
}
<a asp-page="./Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex + 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @nextDisabled">
Next
</a>

View File

@ -1,12 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using ContosoUniversity.Models;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using ContosoUniversity.Data;
using ContosoUniversity.Models;
using System;
using System.Linq;
using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Students
{
@ -20,13 +17,17 @@ namespace ContosoUniversity.Pages.Students
}
public PaginatedList<Student> Student { get; set; }
public string NameSort { get; set; }
public string DateSort { get; set; }
public string CurrentFilter { get; set; }
public string CurrentSort { get; set; }
public async Task OnGetAsync(string sortOrder,
string currentFilter, string searchString, int? pageIndex)
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSort"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSort"] = sortOrder == "Date" ? "date_desc" : "Date";
CurrentSort = sortOrder;
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
if (searchString != null)
{
pageIndex = 1;
@ -36,7 +37,7 @@ namespace ContosoUniversity.Pages.Students
searchString = currentFilter;
}
ViewData["CurrentFilter"] = searchString;
CurrentFilter = searchString;
IQueryable<Student> studentIQ = from s in _context.Students
select s;

View File

@ -7,7 +7,7 @@
<h2>Delete</h2>
<p class="text-danger">@ViewData["ErrorMessage"]</p>
<p class="text-danger">@Model.ErrorMessage</p>
<h3>Are you sure you want to delete this?</h3>
<div>

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Students
{
#region snippet1
public class DeleteModel : PageModel
{
private readonly ContosoUniversity.Data.SchoolContext _context;
@ -17,6 +18,8 @@ namespace ContosoUniversity.Pages.Students
[BindProperty]
public Student Student { get; set; }
public string ErrorMessage { get; set; }
#endregion
#region snippet_OnGetAsync
public async Task<IActionResult> OnGetAsync(int? id, bool? saveChangesError = false)
@ -28,7 +31,7 @@ namespace ContosoUniversity.Pages.Students
Student = await _context.Students
.AsNoTracking()
.FirstOrDefaultAsync (m => m.ID == id);
.FirstOrDefaultAsync(m => m.ID == id);
if (Student == null)
{
@ -37,7 +40,7 @@ namespace ContosoUniversity.Pages.Students
if (saveChangesError.GetValueOrDefault())
{
ViewData["ErrorMessage"] = "Delete failed. Try again";
ErrorMessage = "Delete failed. Try again";
}
return Page();
@ -54,7 +57,7 @@ namespace ContosoUniversity.Pages.Students
var student = await _context.Students
.AsNoTracking()
.FirstOrDefaultAsync (m => m.ID == id);
.FirstOrDefaultAsync(m => m.ID == id);
if (student == null)
{
@ -70,7 +73,7 @@ namespace ContosoUniversity.Pages.Students
catch (DbUpdateException /* ex */)
{
//Log the error (uncomment ex variable name and write a log.)
return RedirectToAction("./Delete",
return RedirectToAction("./Delete",
new { id = id, saveChangesError = true });
}
}

View File

@ -14,7 +14,7 @@
<form sp-page="./Index" method="get">
<div class="form-actions no-color">
<p>
Find by name: <input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
Find by name: <input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-page="./Index">Back to full List</a>
</p>
@ -25,8 +25,8 @@
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["NameSort"]"
asp-route-currentFilter="@ViewData["CurrentFilter"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
</th>
@ -34,8 +34,8 @@
@Html.DisplayNameFor(model => model.Student[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["DateSort"]"
asp-route-currentFilter="@ViewData["CurrentFilter"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort"
asp-route-currentFilter="@Model.CurrentFilter">
@Html.DisplayNameFor(model => model.Student[0].EnrollmentDate)
</a>
</th>
@ -70,16 +70,16 @@
}
<a asp-page="./Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex - 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @prevDisabled">
Previous
</a>
<a asp-page="./Index"
asp-route-sortOrder="@ViewData["CurrentSort"]"
asp-route-sortOrder="@Model.CurrentSort"
asp-route-pageIndex="@(Model.Student.PageIndex + 1)"
asp-route-currentFilter="@ViewData["CurrentFilter"]"
asp-route-currentFilter="@Model.CurrentFilter"
class="btn btn-default @nextDisabled">
Next
</a>

View File

@ -10,6 +10,7 @@ using System.Threading.Tasks;
namespace ContosoUniversity.Pages.Students
{
#region snippet1
public class IndexModel : PageModel
{
private readonly ContosoUniversity.Data.SchoolContext _context;
@ -19,6 +20,12 @@ namespace ContosoUniversity.Pages.Students
_context = context;
}
public string NameSort { get; set; }
public string DateSort { get; set; }
public string CurrentFilter { get; set; }
public string CurrentSort { get; set; }
#endregion
#if SortFilterPage
#region snippet_SortFilterPageType
public PaginatedList<Student> Student { get; set; }
@ -41,8 +48,8 @@ namespace ContosoUniversity.Pages.Students
public async Task OnGetAsync(string sortOrder)
{
#region snippet_Ternary
ViewData["NameSort"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSort"] = sortOrder == "Date" ? "date_desc" : "Date";
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
#endregion
IQueryable<Student> studentIQ = from s in _context.Students
@ -74,9 +81,9 @@ namespace ContosoUniversity.Pages.Students
#region snippet_SortFilter
public async Task OnGetAsync(string sortOrder, string searchString)
{
ViewData["NameSort"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSort"] = sortOrder == "Date" ? "date_desc" : "Date";
ViewData["CurrentFilter"] = searchString;
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
CurrentFilter = searchString;
IQueryable<Student> studentIQ = from s in _context.Students
select s;
@ -113,9 +120,9 @@ namespace ContosoUniversity.Pages.Students
string currentFilter, string searchString, int? pageIndex)
#endregion
{
ViewData["CurrentSort"] = sortOrder;
ViewData["NameSort"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
ViewData["DateSort"] = sortOrder == "Date" ? "date_desc" : "Date";
CurrentSort = sortOrder;
NameSort = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
DateSort = sortOrder == "Date" ? "date_desc" : "Date";
#region snippet_SortFilterPage3
if (searchString != null)
{
@ -127,7 +134,7 @@ namespace ContosoUniversity.Pages.Students
}
#endregion
ViewData["CurrentFilter"] = searchString;
CurrentFilter = searchString;
IQueryable<Student> studentIQ = from s in _context.Students
select s;

View File

@ -14,7 +14,7 @@
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["NameSort"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
</th>
@ -22,7 +22,7 @@
@Html.DisplayNameFor(model => model.Student[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["DateSort"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort">
@Html.DisplayNameFor(model => model.Student[0].EnrollmentDate)
</a>
</th>

View File

@ -15,7 +15,7 @@
<div class="form-actions no-color">
<p>
Find by name:
<input type="text" name="SearchString" value="@ViewData["currentFilter"]" />
<input type="text" name="SearchString" value="@Model.CurrentFilter" />
<input type="submit" value="Search" class="btn btn-default" /> |
<a asp-page="./Index">Back to full List</a>
</p>
@ -26,7 +26,7 @@
<thead>
<tr>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["NameSort"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.NameSort">
@Html.DisplayNameFor(model => model.Student[0].LastName)
</a>
</th>
@ -34,7 +34,7 @@
@Html.DisplayNameFor(model => model.Student[0].FirstMidName)
</th>
<th>
<a asp-page="./Index" asp-route-sortOrder="@ViewData["DateSort"]">
<a asp-page="./Index" asp-route-sortOrder="@Model.DateSort">
@Html.DisplayNameFor(model => model.Student[0].EnrollmentDate)
</a>
</th>

View File

@ -27,6 +27,11 @@ If you run into problems you can't solve, download the [completed app for this s
## Add sorting to the Index page
Add strings to the *Students/Index.cshtml.cs* `PageModel` to contain the sorting paramaters:
[!code-csharp[Main](intro/samples/cu/Pages/Students/Index.cshtml.cs?name=snippet1&highlight=10-13)]
Update the *Students/Index.cshtml.cs* `OnGetAsync` with the following code:
[!code-csharp[Main](intro/samples/cu/Pages/Students/Index.cshtml.cs?name=snippet_SortOnly)]
@ -38,17 +43,15 @@ The `sortOrder` parameter is either "Name" or "Date." The `sortOrder` parameter
When the Index page is requested from the **Students** link, there's no query string. The students are displayed in ascending order by last name. Ascending order by last name is the default (fall-through case) in the `switch` statement. When the user clicks a column heading link, the appropriate `sortOrder` value is provided in the query string value.
The two `ViewData` elements (`NameSort` and `DateSort`) are used by the Razor Page to configure the column heading hyperlinks with the appropriate query string values:
`NameSort` and `DateSort` are used by the Razor Page to configure the column heading hyperlinks with the appropriate query string values:
[!code-csharp[Main](intro/samples/cu/Pages/Students/Index.cshtml.cs?name=snippet_SortOnly&highlight=3-4)]
`ViewData` is a [ViewDataDictionary](/aspnet/core/api/microsoft.aspnetcore.mvc.viewfeatures.viewdatadictionary) object accessed through `string` keys. `ViewData` provides a convenient way to pass data from a Razor Page to a code-behind file, and from a code-behind file to a Razor Page. For more information, see [Weakly typed data (ViewData and ViewBag)](xref:mvc/views/overview#VD_VB) and [ViewData](xref:mvc/views/overview#VD).
The following code contains the C# [?: operator](https://docs.microsoft.com/dotnet/csharp/language-reference/operators/conditional-operator):
[!code-csharp[Main](intro/samples/cu/Pages/Students/Index.cshtml.cs?name=snippet_Ternary)]
The first line specifies that when `sortOrder` is null or empty, `NameSort` is set to "name_desc." If `sortOrder` is **not** null or empty, `NameSort` is set to an empty string.
The first line specifies that when `sortOrder` is null or empty, `NameSort` is set to "name_desc." If `sortOrder` is **not** null or empty, `NameSort` is set to an empty string.
The `?: operator` is also known as the ternary operator.
@ -80,7 +83,7 @@ Replace the code in *Students/Index.cshtml*, with the following highlighted code
The preceding code:
* Adds hyperlinks to the `LastName` and `EnrollmentDate` column headings.
* Uses the information in `ViewData` dictionary to set up hyperlinks with the current sort order values.
* Uses the information in `NameSort` and `DateSort` to set up hyperlinks with the current sort order values.
To verify that sorting works:
@ -91,7 +94,7 @@ To verify that sorting works:
To get a better understanding of the code:
* In *Student/Index.cshtml.cs*, set a breakpoint on `switch (sortOrder)`.
* Add a watch for `ViewData["NameSort"]` and `ViewData["DateSort"]`.
* Add a watch for `NameSort` and `DateSort`.
* In *Student/Index.cshtml*, set a breakpoint on `@Html.DisplayNameFor(model => model.Student[0].LastName)`.
Step through the debugger.
@ -185,9 +188,9 @@ All the parameters are null when:
When a paging link is clicked, the page index variable contains the page number to display.
`ViewData["CurrentSort"]` provides the Razor Page with the current sort order. The current sort order must be included in the paging links to keep the sort order while paging.
`CurrentSort` provides the Razor Page with the current sort order. The current sort order must be included in the paging links to keep the sort order while paging.
`ViewData["CurrentFilter"]` provides the Razor Page with the current filter string. The `ViewData["CurrentFilter"]` value:
`CurrentFilter` provides the Razor Page with the current filter string. The `CurrentFilter` value:
* Must be included in the paging links in order to maintain the filter settings during paging.
* Must be restored to the text box when the page is redisplayed.
@ -229,7 +232,7 @@ Run the app and navigate to the students page.
To get a better understanding of the code:
* In *Student/Index.cshtml.cs*, set a breakpoint on `switch (sortOrder)`.
* Add a watch for `ViewData["NameSort"]`, `ViewData["DateSort"]`, ViewData["CurrentSort"], and `Model.Student.PageIndex`.
* Add a watch for `NameSort`, `DateSort`, `CurrentSort`, and `Model.Student.PageIndex`.
* In *Student/Index.cshtml*, set a breakpoint on `@Html.DisplayNameFor(model => model.Student[0].LastName)`.
Step through the debugger.