From 5c2d73fced42ab2809c3cc297ec4bf22a15de0cf Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Mon, 29 Jan 2018 19:39:34 -0600 Subject: [PATCH 1/4] Link repairs (#5302) --- aspnetcore/fundamentals/error-handling.md | 2 +- aspnetcore/migration/mvc.md | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/aspnetcore/fundamentals/error-handling.md b/aspnetcore/fundamentals/error-handling.md index d6d18b08fb..73df297fca 100644 --- a/aspnetcore/fundamentals/error-handling.md +++ b/aspnetcore/fundamentals/error-handling.md @@ -114,7 +114,7 @@ Hosting can only show an error page for a captured startup error if the error oc ## ASP.NET MVC error handling -[MVC](../mvc/index.md) apps have some additional options for handling errors, such as configuring exception filters and performing model validation. +[MVC](xref:mvc/overview) apps have some additional options for handling errors, such as configuring exception filters and performing model validation. ### Exception Filters diff --git a/aspnetcore/migration/mvc.md b/aspnetcore/migration/mvc.md index 0a7188ce4f..0925d9068e 100644 --- a/aspnetcore/migration/mvc.md +++ b/aspnetcore/migration/mvc.md @@ -89,7 +89,7 @@ Run the app. ![Web application open in Microsoft Edge](mvc/_static/hello-world.png) -See [Controllers](../mvc/controllers/index.md) and [Views](../mvc/views/index.md) for more information. +See [Controllers](xref:mvc/controllers/actions) and [Views](xref:mvc/views/overview) for more information. Now that we have a minimal working ASP.NET Core project, we can start migrating functionality from the ASP.NET MVC project. We will need to move the following: @@ -151,7 +151,7 @@ See [Manage Client-Side Packages with Bower](../client-side/bower.md) for more i * Create a *Views/Shared* folder. -* *Optional:* Copy *_ViewImports.cshtml* from the *FullAspNetCore* MVC project's *Views* folder into the ASP.NET Core project's *Views* folder. Remove any namespace declaration in the *_ViewImports.cshtml* file. The *_ViewImports.cshtml* file provides namespaces for all the view files and brings in [Tag Helpers](../mvc/views/tag-helpers/index.md). Tag Helpers are used in the new layout file. The *_ViewImports.cshtml* file is new for ASP.NET Core. +* *Optional:* Copy *_ViewImports.cshtml* from the *FullAspNetCore* MVC project's *Views* folder into the ASP.NET Core project's *Views* folder. Remove any namespace declaration in the *_ViewImports.cshtml* file. The *_ViewImports.cshtml* file provides namespaces for all the view files and brings in [Tag Helpers](xref:mvc/views/tag-helpers/intro). Tag Helpers are used in the new layout file. The *_ViewImports.cshtml* file is new for ASP.NET Core. * Copy the *_Layout.cshtml* file from the old ASP.NET MVC project's *Views/Shared* folder into the ASP.NET Core project's *Views/Shared* folder. @@ -186,7 +186,7 @@ The updated *_Layout.cshtml* file is shown below: View the site in the browser. It should now load correctly, with the expected styles in place. -* *Optional:* You might want to try using the new layout file. For this project you can copy the layout file from the *FullAspNetCore* project. The new layout file uses [Tag Helpers](../mvc/views/tag-helpers/index.md) and has other improvements. +* *Optional:* You might want to try using the new layout file. For this project you can copy the layout file from the *FullAspNetCore* project. The new layout file uses [Tag Helpers](xref:mvc/views/tag-helpers/intro) and has other improvements. ## Configure bundling and minification From e43f7f3c43e64bb1eca46b2117a39340fca8d70a Mon Sep 17 00:00:00 2001 From: Luke Latham <1622880+guardrex@users.noreply.github.com> Date: Mon, 29 Jan 2018 21:06:54 -0600 Subject: [PATCH 2/4] Update link to AI in Environments topic --- aspnetcore/fundamentals/environments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aspnetcore/fundamentals/environments.md b/aspnetcore/fundamentals/environments.md index 52f94a258a..1d0eb7e784 100644 --- a/aspnetcore/fundamentals/environments.md +++ b/aspnetcore/fundamentals/environments.md @@ -88,7 +88,7 @@ The production environment should be configured to maximize security, performanc * Client-side resources are bundled, minified, and potentially served from a CDN. * Diagnostic error pages disabled. * Friendly error pages enabled. -* Production logging and monitoring enabled. For example, [Application Insights](https://azure.microsoft.com/documentation/articles/app-insights-asp-net-five/). +* Production logging and monitoring enabled. For example, [Application Insights](/azure/application-insights/app-insights-asp-net-core). ## Setting the environment From a694848b01374fa0a454e029a43785c7fed82a91 Mon Sep 17 00:00:00 2001 From: James Alt Date: Mon, 29 Jan 2018 22:26:51 -0600 Subject: [PATCH 3/4] Change label from XML to JSON (#5306) --- aspnetcore/fundamentals/environments.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/aspnetcore/fundamentals/environments.md b/aspnetcore/fundamentals/environments.md index 52f94a258a..4b8a7fccd8 100644 --- a/aspnetcore/fundamentals/environments.md +++ b/aspnetcore/fundamentals/environments.md @@ -45,9 +45,9 @@ The development environment can enable features that shouldn't be exposed in pro The environment for local machine development can be set in the *Properties\launchSettings.json* file of the project. Environment values set in *launchSettings.json* override values set in the system environment. -The following XML shows three profiles from a *launchSettings.json* file: +The following JSON shows three profiles from a *launchSettings.json* file: -[!code-xml[Main](environments/sample/WebApp1/Properties/launchSettings.json?highlight=10,11,18,26)] +[!code-json[Main](environments/sample/WebApp1/Properties/launchSettings.json?highlight=10,11,18,26)] When the application is launched with `dotnet run`, the first profile with `"commandName": "Project"` will be used. The value of `commandName` specifies the web server to launch. `commandName` can be one of : @@ -144,7 +144,7 @@ export ASPNETCORE_ENVIRONMENT=Development ``` Machine level environment variables are set in the *.bashrc* or *.bash_profile* file. Edit the file using any text editor and add the following statment. -``` +```bash export ASPNETCORE_ENVIRONMENT=Development ``` From 1a9e722358472d8d9c29b3bbaf6aa78dd033549d Mon Sep 17 00:00:00 2001 From: Rick Anderson Date: Mon, 29 Jan 2018 21:29:50 -1000 Subject: [PATCH 4/4] Extend RP tutorial to Mac and VSC (#5303) * Extend RP tutorial to Mac and VSC * work * work * work * work * work * work --- aspnetcore/includes/RP/code/Models/Movie.cs | 4 + aspnetcore/includes/RP/da1.md | 13 +++ aspnetcore/includes/RP/da2.md | 84 ++++++++++++++++ aspnetcore/includes/RP/search.md | 96 +++++++++++++++++++ aspnetcore/toc.md | 29 +++--- aspnetcore/tutorials/razor-pages-mac/da1.md | 19 ++++ aspnetcore/tutorials/razor-pages-mac/index.md | 4 +- aspnetcore/tutorials/razor-pages-mac/page.md | 2 +- .../tutorials/razor-pages-mac/search.md | 18 ++++ aspnetcore/tutorials/razor-pages-mac/sql.md | 2 +- aspnetcore/tutorials/razor-pages-vsc/da1.md | 19 ++++ aspnetcore/tutorials/razor-pages-vsc/index.md | 5 +- .../tutorials/razor-pages-vsc/search.md | 18 ++++ aspnetcore/tutorials/razor-pages-vsc/sql.md | 2 +- aspnetcore/tutorials/razor-pages/da1.md | 91 +----------------- 15 files changed, 298 insertions(+), 108 deletions(-) create mode 100644 aspnetcore/includes/RP/da1.md create mode 100644 aspnetcore/includes/RP/da2.md create mode 100644 aspnetcore/includes/RP/search.md create mode 100644 aspnetcore/tutorials/razor-pages-mac/da1.md create mode 100644 aspnetcore/tutorials/razor-pages-mac/search.md create mode 100644 aspnetcore/tutorials/razor-pages-vsc/da1.md create mode 100644 aspnetcore/tutorials/razor-pages-vsc/search.md diff --git a/aspnetcore/includes/RP/code/Models/Movie.cs b/aspnetcore/includes/RP/code/Models/Movie.cs index 3b72b3f679..7ea500b2d7 100644 --- a/aspnetcore/includes/RP/code/Models/Movie.cs +++ b/aspnetcore/includes/RP/code/Models/Movie.cs @@ -1,4 +1,5 @@ using System; +using System.ComponentModel.DataAnnotations; namespace RazorPagesMovie.Models { @@ -6,6 +7,9 @@ namespace RazorPagesMovie.Models { 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; } public decimal Price { get; set; } diff --git a/aspnetcore/includes/RP/da1.md b/aspnetcore/includes/RP/da1.md new file mode 100644 index 0000000000..5e55f62a09 --- /dev/null +++ b/aspnetcore/includes/RP/da1.md @@ -0,0 +1,13 @@ +# Update the generated pages + +By [Rick Anderson](https://twitter.com/RickAndMSFT) + +We have a good start to the movie app, but the presentation isn't ideal. We don't want to see the time (12:00:00 AM in the image below) and **ReleaseDate** should be **Release Date** (two words). + +![Movie application open in Chrome showing movie data](../../tutorials/razor-pages/sql/_static/m55.png) + +## Update the generated code + +Open the *Models/Movie.cs* file and add the highlighted lines shown in the following code: + +[!code-csharp[Main](code/Models/Movie.cs?highlight=2,11-12)] diff --git a/aspnetcore/includes/RP/da2.md b/aspnetcore/includes/RP/da2.md new file mode 100644 index 0000000000..b0329a670b --- /dev/null +++ b/aspnetcore/includes/RP/da2.md @@ -0,0 +1,84 @@ +We'll cover [DataAnnotations](https://docs.microsoft.com/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-6) in the next tutorial. The [Display](https://docs.microsoft.com//aspnet/core/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/aspnet/core/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. + +Browse to Pages/Movies and hover over an **Edit** link to see the target URL. + +![Browser window with mouse over the Edit link and a link Url of http://localhost:1234/Movies/Edit/5 is shown](../../tutorials/razor-pages/da1/edit7.png) + +The **Edit**, **Details**, and **Delete** links are generated by the [Anchor Tag Helper](xref:mvc/views/tag-helpers/builtin-th/anchor-tag-helper) +in the *Pages/Movies/Index.cshtml* file. + +[!code-cshtml[Main](../../tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Index.cshtml?highlight=16-18&range=32-)] + +[Tag Helpers](xref:mvc/views/tag-helpers/intro) 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](xref:mvc/razor-pages/index#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: + +```html + + 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: + + ```cshtml +@page "{id:int?}" +``` + +### Update concurrency exception handling + +Update the `OnPostAsync` method in the *Pages/Movies/Edit.cshtml.cs* file. The following highlighted code shows the changes: + +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit.cshtml.cs?name=snippet1&highlight=16-23)] + +The previous code only detects concurrency exceptions when the first concurrent client deletes the movie, and the second concurrent client posts changes to the movie. + +To test the `catch` block: + +* Set a breakpoint on `catch (DbUpdateConcurrencyException)` +* Edit a movie. +* In another browser window, select the **Delete** link for the same movie, and then delete the movie. +* In the previous browser window, post changes to the movie. + +Production code would generally detect concurrency conflicts when two or more clients concurrently updated a record. See [Handling concurrency conflicts](xref:data/ef-rp/concurrency) for more information. + +### Posting and binding review + +Examine the *Pages/Movies/Edit.cshtml.cs* file: +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit.cshtml.cs?name=snippet2)] + +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](xref:mvc/models/model-binding). + + ```csharp + [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. + +Search is added in the next tutorial. \ No newline at end of file diff --git a/aspnetcore/includes/RP/search.md b/aspnetcore/includes/RP/search.md new file mode 100644 index 0000000000..aa32c376a2 --- /dev/null +++ b/aspnetcore/includes/RP/search.md @@ -0,0 +1,96 @@ +# Adding search to a Razor Pages app + +By [Rick Anderson](https://twitter.com/RickAndMSFT) + +In this document, search capability is added to the Index page that enables searching movies by *genre* or *name*. + +Update the Index page's `OnGetAsync` method with the following code: + +[!code-cshtml[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/_ViewStart.cshtml)] + +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/Index.cshtml.cs?name=snippet_1stSearch)] + +The first line of the `OnGetAsync` method creates a [LINQ](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/linq/) query to select the movies: + +```csharp +var movies = from m in _context.Movie + select m; +``` + +The query is *only* defined at this point, it has **not** been run against the database. + +If the `searchString` parameter contains a string, the movies query is modified to filter on the search string: + +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/Index.cshtml.cs?name=snippet_SearchNull)] + +The `s => s.Title.Contains()` code is a [Lambda Expression](https://docs.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions). Lambdas are used in method-based [LINQ](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/linq/) queries as arguments to standard query operator methods such as the [Where](https://docs.microsoft.com/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq) method or `Contains` (used in the preceding code). LINQ queries are not executed when they're defined or when they're modified by calling a method (such as `Where`, `Contains` or `OrderBy`). Rather, query execution is deferred. That means the evaluation of an expression is delayed until its realized value is iterated over or the `ToListAsync` method is called. See [Query Execution](https://docs.microsoft.com/dotnet/framework/data/adonet/ef/language-reference/query-execution) for more information. + +**Note:** The [Contains](https://docs.microsoft.com//dotnet/api/system.data.objects.dataclasses.entitycollection-1.contains) method is run on the database, not in the C# code. The case sensitivity on the query depends on the database and the collation. On SQL Server, `Contains` maps to [SQL LIKE](https://docs.microsoft.com/sql/t-sql/language-elements/like-transact-sql), which is case insensitive. In SQLite, with the default collation, it's case sensitive. + +Navigate to the Movies page and append a query string such as `?searchString=Ghost` to the URL (for example, `http://localhost:5000/Movies?searchString=Ghost`). The filtered movies are displayed. + +![Index view](../../tutorials/razor-pages/search/_static/ghost.png) + +If the following route template is added to the Index page, the search string can be passed as a URL segment (for example, `http://localhost:5000/Movies/ghost`). + +```cshtml +@page "{searchString?}" +``` + +The preceding route constraint allows searching the title as route data (a URL segment) instead of as a query string value. The `?` in `"{searchString?}"` means this is an optional route parameter. + +![Index view with the word ghost added to the Url and a returned movie list of two movies, Ghostbusters and Ghostbusters 2](../../tutorials/razor-pages/search/_static/g2.png) + +However, you can't expect users to modify the URL to search for a movie. In this step, UI is added to filter movies. If you added the route constraint `"{searchString?}"`, remove it. + +Open the *Pages/Movies/Index.cshtml* file, and add the `
` markup highlighted in the following code: + +[!code-cshtml[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/Index2.cshtml?highlight=14-19&range=1-22)] + +The HTML `` tag uses the [Form Tag Helper](xref:mvc/views/working-with-forms#the-form-tag-helper). When the form is submitted, the filter string is sent to the *Pages/Movies/Index* page. Save the changes and test the filter. + +![Index view with the word ghost typed into the Title filter textbox](../../tutorials/razor-pages/search/_static/filter.png) + +## Search by genre + +Add the the following highlighted properties to *Pages/Movies/Index.cshtml.cs*: + +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/Index.cshtml.cs?name=snippet_newProps&highlight=11-)] + +The `SelectList Genres` contains the list of genres. This allows the user to select a genre from the list. + +The `MovieGenre` property contains the specific genre the user selects (for example, "Western"). + +Update the `OnGetAsync` method with the following code: + +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/Index.cshtml.cs?name=snippet_SearchGenre)] + +The following code is a LINQ query that retrieves all the genres from the database. + +[!code-csharp[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/Index.cshtml.cs?name=snippet_LINQ)] + +The `SelectList` of genres is created by projecting the distinct genres. + + + +```csharp +Genres = new SelectList(await genreQuery.Distinct().ToListAsync()); +``` + +### Adding search by genre + +Update *Index.cshtml* as follows: + +[!code-cshtml[Main](../../tutorials/razor-pages/razor-pages-start/sample/RazorPagesMovie/Pages/Movies/IndexFormGenreNoRating.cshtml?highlight=16-18&range=1-26)] + +Test the app by searching by genre, by movie title, and by both. + +>[!div class="step-by-step"] +[Previous: Updating the pages](xref:tutorials/razor-pages/da1) +[Next: Adding a new field](xref:tutorials/razor-pages/new-field) diff --git a/aspnetcore/toc.md b/aspnetcore/toc.md index 95ced93c44..e96f30e68a 100644 --- a/aspnetcore/toc.md +++ b/aspnetcore/toc.md @@ -28,6 +28,21 @@ ### [Examine the Details and Delete methods](tutorials/first-mvc-app/details.md) ## [Cross platform tutorials](xref:tutorials/xplat) +### [Razor Pages web app on a Mac](xref:tutorials/razor-pages-mac/index) +#### [Getting started with Razor Pages](xref:tutorials/razor-pages-mac/razor-pages-start) +#### [Adding a model](xref:tutorials/razor-pages-mac/model) +#### [Scaffolded Razor Pages](xref:tutorials/razor-pages-mac/page) +#### [Working with SQLite](xref:tutorials/razor-pages-mac/sql) +#### [Update the pages](xref:tutorials/razor-pages-mac/da1) +#### [Add search](xref:tutorials/razor-pages-mac/search) + + +### [Razor Pages web app with VS Code](xref:tutorials/razor-pages-vsc/index) +#### [Getting started with Razor Pages](xref:tutorials/razor-pages-vsc/razor-pages-start) +#### [Adding a model](xref:tutorials/razor-pages-vsc/model) +#### [Scaffolded Razor Pages](xref:tutorials/razor-pages-vsc/page) +#### [Working with SQLite](xref:tutorials/razor-pages-vsc/sql) +#### [Update the pages](xref:tutorials/razor-pages-vsc/da1) ### [MVC web app with Visual Studio for Mac](xref:tutorials/first-mvc-app-mac/index) #### [Getting started](xref:tutorials/first-mvc-app-mac/start-mvc) @@ -41,7 +56,7 @@ #### [Adding Validation](xref:tutorials/first-mvc-app-mac/validation) #### [Examining the Details and Delete methods](xref:tutorials/first-mvc-app/details) -### [Web app with Visual Studio Code on Mac or Linux](xref:tutorials/first-mvc-app-xplat/index) +### [MVC web app with Visual Studio Code on Mac or Linux](xref:tutorials/first-mvc-app-xplat/index) #### [Getting started](tutorials/first-mvc-app-xplat/start-mvc.md) #### [Adding a controller](tutorials/first-mvc-app-xplat/adding-controller.md) #### [Adding a view](tutorials/first-mvc-app-xplat/adding-view.md) @@ -53,18 +68,6 @@ #### [Adding Validation](tutorials/first-mvc-app-xplat/validation.md) #### [Examining the Details and Delete methods](tutorials/first-mvc-app/details.md) - -### [Razor Pages web app on a Mac](xref:tutorials/razor-pages-mac/index) -#### [Getting started with Razor Pages](xref:tutorials/razor-pages-mac/razor-pages-start) -#### [Adding a model](xref:tutorials/razor-pages-mac/model) -#### [Scaffolded Razor Pages](xref:tutorials/razor-pages-mac/page) -#### [Working with SQLite](xref:tutorials/razor-pages-mac/sql) -### [Razor Pages web app with VS Code](xref:tutorials/razor-pages-vsc/index) -#### [Getting started with Razor Pages](xref:tutorials/razor-pages-vsc/razor-pages-start) -#### [Adding a model](xref:tutorials/razor-pages-vsc/model) -#### [Scaffolded Razor Pages](xref:tutorials/razor-pages-vsc/page) -#### [Working with SQLite](xref:tutorials/razor-pages-vsc/sql) - ### [Web API with Visual Studio for Mac](xref:tutorials/first-web-api-mac) ### [Web API with Visual Studio Code](xref:tutorials/web-api-vsc) diff --git a/aspnetcore/tutorials/razor-pages-mac/da1.md b/aspnetcore/tutorials/razor-pages-mac/da1.md new file mode 100644 index 0000000000..70dda0e5a5 --- /dev/null +++ b/aspnetcore/tutorials/razor-pages-mac/da1.md @@ -0,0 +1,19 @@ +--- +title: Update the generated pages +author: rick-anderson +description: Update the generated pages with better display. +manager: wpickett +ms.author: riande +ms.date: 08/07/2017 +ms.prod: asp.net-core +ms.technology: aspnet +ms.topic: get-started-article +uid: tutorials/razor-pages-mac/da1 +--- +[!INCLUDE[model1](../../includes/RP/da1.md)] + +[!INCLUDE[model1](../../includes/RP/da2.md)] + +>[!div class="step-by-step"] +[Previous: Working with SQLlite](xref:tutorials/razor-pages-mac/sql) +[Adding Search](xref:tutorials/razor-pages-mac/search) diff --git a/aspnetcore/tutorials/razor-pages-mac/index.md b/aspnetcore/tutorials/razor-pages-mac/index.md index b3738a4d5b..f8e6a6e4a1 100644 --- a/aspnetcore/tutorials/razor-pages-mac/index.md +++ b/aspnetcore/tutorials/razor-pages-mac/index.md @@ -22,11 +22,11 @@ This series explains the basics of building a Razor Pages web app with ASP.NET C 1. [Adding a model to a Razor Pages app](xref:tutorials/razor-pages-mac/model) 1. [Scaffolded Razor Pages](xref:tutorials/razor-pages-mac/page) 1. [Working with SQLite](xref:tutorials/razor-pages-mac/sql) +1. [Update the pages](xref:tutorials/razor-pages-mac/da1) +1. [Adding search](xref:tutorials/razor-pages-mac/search) Until the next section is complete, follow the Visual Studio for Windows version. -1. [Updating the pages](xref:tutorials/razor-pages/da1) -1. [Adding search](xref:tutorials/razor-pages/search) 1. [Adding a new field](xref:tutorials/razor-pages/new-field) 1. [Adding validation](xref:tutorials/razor-pages/validation) diff --git a/aspnetcore/tutorials/razor-pages-mac/page.md b/aspnetcore/tutorials/razor-pages-mac/page.md index b5332ba43b..39d3e81b12 100644 --- a/aspnetcore/tutorials/razor-pages-mac/page.md +++ b/aspnetcore/tutorials/razor-pages-mac/page.md @@ -19,4 +19,4 @@ The next tutorial explains SQLite and seeding the database. >[!div class="step-by-step"] [Previous: Adding a model](xref:tutorials/razor-pages-mac/model) -[Next: SQLite](xref:tutorials/razor-pages-mac/sql) +[Next: SQLite ](xref:tutorials/razor-pages-mac/sql) diff --git a/aspnetcore/tutorials/razor-pages-mac/search.md b/aspnetcore/tutorials/razor-pages-mac/search.md new file mode 100644 index 0000000000..35aacc0911 --- /dev/null +++ b/aspnetcore/tutorials/razor-pages-mac/search.md @@ -0,0 +1,18 @@ +--- +title: Adding search to ASP.NET Core Razor Pages +author: rick-anderson +description: Shows how to add search to ASP.NET Core Razor Pages +manager: wpickett +ms.author: riande +ms.date: 08/07/2017 +ms.prod: asp.net-core +ms.technology: aspnet +ms.topic: get-started-article +uid: tutorials/razor-pages-mac/search +--- + +[!INCLUDE[Search](../../includes/RP/search.md)] + +>[!div class="step-by-step"] +[Previous: Updating the pages](xref:tutorials/razor-pages-mac/da1) +[Next: Adding a new field](xref:tutorials/razor-pages/new-field) diff --git a/aspnetcore/tutorials/razor-pages-mac/sql.md b/aspnetcore/tutorials/razor-pages-mac/sql.md index 4591ff7e29..bf6f568d8e 100644 --- a/aspnetcore/tutorials/razor-pages-mac/sql.md +++ b/aspnetcore/tutorials/razor-pages-mac/sql.md @@ -16,4 +16,4 @@ uid: tutorials/razor-pages-mac/sql >[!div class="step-by-step"] [Previous: Adding a model](xref:tutorials/razor-pages-mac/model) -[Next: Updating the pages](xref:tutorials/razor-pages/da1) +[Next: Update the pages](xref:tutorials/razor-pages-mac/da1) diff --git a/aspnetcore/tutorials/razor-pages-vsc/da1.md b/aspnetcore/tutorials/razor-pages-vsc/da1.md new file mode 100644 index 0000000000..1401f0f56a --- /dev/null +++ b/aspnetcore/tutorials/razor-pages-vsc/da1.md @@ -0,0 +1,19 @@ +--- +title: Update the generated pages +author: rick-anderson +description: Update the generated pages with better display. +manager: wpickett +ms.author: riande +ms.date: 08/07/2017 +ms.prod: asp.net-core +ms.technology: aspnet +ms.topic: get-started-article +uid: tutorials/razor-pages-vsc/da1 +--- +[!INCLUDE[model1](../../includes/RP/da1.md)] + +[!INCLUDE[model1](../../includes/RP/da2.md)] + +>[!div class="step-by-step"] +[Previous: Working with SQLlite](xref:tutorials/razor-pages-vsc/sql) +[Adding Search](xref:tutorials/razor-pages/search) diff --git a/aspnetcore/tutorials/razor-pages-vsc/index.md b/aspnetcore/tutorials/razor-pages-vsc/index.md index 65e997dbc0..3267ccb9f2 100644 --- a/aspnetcore/tutorials/razor-pages-vsc/index.md +++ b/aspnetcore/tutorials/razor-pages-vsc/index.md @@ -11,7 +11,6 @@ ms.topic: get-started-article uid: tutorials/razor-pages-vsc/index --- - # Create a Razor Pages web app with ASP.NET Core and Visual Studio Code This is a work in progress. @@ -22,10 +21,10 @@ This series explains the basics of building a Razor Pages web app with ASP.NET C 1. [Adding a model to a Razor Pages app](xref:tutorials/razor-pages-vsc/model) 1. [Scaffolded Razor Pages] (xref:tutorials/razor-pages-vsc/page) 1. [Working with SQLite](xref:tutorials/razor-pages-vsc/sql) +1. [Update the pages](xref:tutorials/razor-pages-vsc/da1) +1. [Adding search](xref:tutorials/razor-pages-vsc/search) Until the next section is complete, follow the Visual Studio for Windows version. -1. [Updating the pages](xref:tutorials/razor-pages/da1) -1. [Adding search](xref:tutorials/razor-pages/search) 1. [Adding a new field](xref:tutorials/razor-pages/new-field) 1. [Adding validation](xref:tutorials/razor-pages/validation) diff --git a/aspnetcore/tutorials/razor-pages-vsc/search.md b/aspnetcore/tutorials/razor-pages-vsc/search.md new file mode 100644 index 0000000000..d7e1d729cd --- /dev/null +++ b/aspnetcore/tutorials/razor-pages-vsc/search.md @@ -0,0 +1,18 @@ +--- +title: Adding search to ASP.NET Core Razor Pages +author: rick-anderson +description: Shows how to add search to ASP.NET Core Razor Pages +manager: wpickett +ms.author: riande +ms.date: 08/07/2017 +ms.prod: asp.net-core +ms.technology: aspnet +ms.topic: get-started-article +uid: tutorials/razor-pages-vsc/search +--- + +[!INCLUDE[Search](../../includes/RP/search.md)] + +>[!div class="step-by-step"] +[Previous: Updating the pages](xref:tutorials/razor-pages-vsc/da1) +[Next: Adding a new field](xref:tutorials/razor-pages/new-field) diff --git a/aspnetcore/tutorials/razor-pages-vsc/sql.md b/aspnetcore/tutorials/razor-pages-vsc/sql.md index 2ac3af06be..ee6a2efa7f 100644 --- a/aspnetcore/tutorials/razor-pages-vsc/sql.md +++ b/aspnetcore/tutorials/razor-pages-vsc/sql.md @@ -16,4 +16,4 @@ uid: tutorials/razor-pages-vsc/sql >[!div class="step-by-step"] [Previous: Adding a model](xref:tutorials/razor-pages-vsc/model) -[Next: Updating the pages](xref:tutorials/razor-pages/da1) +[Next: Update the pages](xref:tutorials/razor-pages-vsc/da1) diff --git a/aspnetcore/tutorials/razor-pages/da1.md b/aspnetcore/tutorials/razor-pages/da1.md index dba5d81c92..e82d5ec24f 100644 --- a/aspnetcore/tutorials/razor-pages/da1.md +++ b/aspnetcore/tutorials/razor-pages/da1.md @@ -1,7 +1,7 @@ --- -title: Updating the generated pages +title: Update the generated pages author: rick-anderson -description: Updating the generated pages with better display. +description: Update the generated pages with better display. manager: wpickett ms.author: riande ms.date: 08/07/2017 @@ -10,7 +10,7 @@ ms.technology: aspnet ms.topic: get-started-article uid: tutorials/razor-pages/da1 --- -# Updating the generated pages +# Update the generated pages By [Rick Anderson](https://twitter.com/RickAndMSFT) @@ -34,90 +34,7 @@ Select `using System.ComponentModel.DataAnnotations;` Visual studio adds `using System.ComponentModel.DataAnnotations;`. -We'll cover [DataAnnotations](https://docs.microsoft.com/aspnet/mvc/overview/older-versions/mvc-music-store/mvc-music-store-part-6) in the next tutorial. The [Display](https://docs.microsoft.com//aspnet/core/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/aspnet/core/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. - -Browse to Pages/Movies and hover over an **Edit** link to see the target URL. - -![Browser window with mouse over the Edit link and a link Url of http://localhost:1234/Movies/Edit/5 is shown](da1/edit7.png) - -The **Edit**, **Details**, and **Delete** links are generated by the [Anchor Tag Helper](xref:mvc/views/tag-helpers/builtin-th/anchor-tag-helper) -in the *Pages/Movies/Index.cshtml* file. - -[!code-cshtml[Main](razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Index.cshtml?highlight=16-18&range=32-)] - -[Tag Helpers](xref:mvc/views/tag-helpers/intro) 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](xref:mvc/razor-pages/index#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: - -```html - - 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: - - ```cshtml -@page "{id:int?}" -``` - -### Update concurrency exception handling - -Update the `OnPostAsync` method in the *Pages/Movies/Edit.cshtml.cs* file. The following highlighted code shows the changes: - -[!code-csharp[Main](razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit.cshtml.cs?name=snippet1&highlight=16-23)] - -The previous code only detects concurrency exceptions when the first concurrent client deletes the movie, and the second concurrent client posts changes to the movie. - -To test the `catch` block: - -* Set a breakpoint on `catch (DbUpdateConcurrencyException)` -* Edit a movie. -* In another browser window, select the **Delete** link for the same movie, and then delete the movie. -* In the previous browser window, post changes to the movie. - -Production code would generally detect concurrency conflicts when two or more clients concurrently updated a record. See [Handling concurrency conflicts](xref:data/ef-rp/concurrency) for more information. - -### Posting and binding review - -Examine the *Pages/Movies/Edit.cshtml.cs* file: -[!code-csharp[Main](razor-pages-start/snapshot_sample/RazorPagesMovie/Pages/Movies/Edit.cshtml.cs?name=snippet2)] - -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](xref:mvc/models/model-binding). - - ```csharp - [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. - -Search is added in the next tutorial. +[!INCLUDE[model1](../../includes/RP/da2.md)] >[!div class="step-by-step"] [Previous: Working with SQL Server LocalDB](xref:tutorials/razor-pages/sql)