From 7da407a17a5a876c2d3ce683cfd6194ea50fa928 Mon Sep 17 00:00:00 2001 From: Praburaj Date: Mon, 16 Feb 2015 17:18:12 -0800 Subject: [PATCH] Using statuscode pages in the sample Adding some automation as well. --- .../Controllers/StoreManagerController.cs | 37 +++--- .../Admin/Views/StoreManager/Details.cshtml | 81 ++++++------- .../Admin/Views/StoreManager/Edit.cshtml | 109 ++++++++---------- .../Controllers/CheckoutController.cs | 6 +- src/MusicStore/Controllers/HomeController.cs | 18 ++- .../Controllers/ShoppingCartController.cs | 6 +- src/MusicStore/Controllers/StoreController.cs | 22 ++-- src/MusicStore/Startup.cs | 9 ++ src/MusicStore/StartupNtlmAuthentication.cs | 10 +- src/MusicStore/StartupOpenIdConnect.cs | 2 + .../Views/Shared/StatusCodePage.cshtml | 6 + test/E2ETests/Implementation/Scenarios.cs | 10 ++ test/E2ETests/SmokeTests.cs | 3 + .../Mocks/StartupOpenIdConnectTesting.cs | 2 + .../shared/Mocks/StartupSocialTesting.cs | 2 + 15 files changed, 166 insertions(+), 157 deletions(-) create mode 100644 src/MusicStore/Views/Shared/StatusCodePage.cshtml diff --git a/src/MusicStore/Areas/Admin/Controllers/StoreManagerController.cs b/src/MusicStore/Areas/Admin/Controllers/StoreManagerController.cs index 32235b741b..6f56f8abb1 100644 --- a/src/MusicStore/Areas/Admin/Controllers/StoreManagerController.cs +++ b/src/MusicStore/Areas/Admin/Controllers/StoreManagerController.cs @@ -6,8 +6,6 @@ using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Infrastructure; -using Microsoft.AspNet.Security; -using Microsoft.Data.Entity; using Microsoft.Framework.Cache.Memory; using MusicStore.Hubs; using MusicStore.Models; @@ -23,18 +21,10 @@ namespace MusicStore.Areas.Admin.Controllers private IHubContext _announcementHub; [FromServices] - public MusicStoreContext DbContext - { - get; - set; - } + public MusicStoreContext DbContext { get; set; } [FromServices] - public IMemoryCache Cache - { - get; - set; - } + public IMemoryCache Cache { get; set; } [FromServices] public IConnectionManager ConnectionManager @@ -84,7 +74,7 @@ namespace MusicStore.Areas.Admin.Controllers if (album == null) { Cache.Remove(cacheKey); - return View(album); + return HttpNotFound(); } return View(album); @@ -135,7 +125,7 @@ namespace MusicStore.Areas.Admin.Controllers if (album == null) { - return View(album); + return HttpNotFound(); } ViewBag.GenreId = new SelectList(DbContext.Genres, "GenreId", "Name", album.GenreId); @@ -168,6 +158,11 @@ namespace MusicStore.Areas.Admin.Controllers public async Task RemoveAlbum(int id) { var album = await DbContext.Albums.Where(a => a.AlbumId == id).FirstOrDefaultAsync(); + if (album == null) + { + return HttpNotFound(); + } + return View(album); } @@ -177,15 +172,16 @@ namespace MusicStore.Areas.Admin.Controllers public async Task RemoveAlbumConfirmed(int id, CancellationToken requestAborted) { var album = await DbContext.Albums.Where(a => a.AlbumId == id).FirstOrDefaultAsync(); - - if (album != null) + if (album == null) { - DbContext.Albums.Remove(album); - await DbContext.SaveChangesAsync(requestAborted); - //Remove the cache entry as it is removed - Cache.Remove(GetCacheKey(id)); + return HttpNotFound(); } + DbContext.Albums.Remove(album); + await DbContext.SaveChangesAsync(requestAborted); + //Remove the cache entry as it is removed + Cache.Remove(GetCacheKey(id)); + return RedirectToAction("Index"); } @@ -199,6 +195,7 @@ namespace MusicStore.Areas.Admin.Controllers // GET: /StoreManager/GetAlbumIdFromName // Note: Added for automated testing purpose. Application does not use this. [HttpGet] + [SkipStatusCodePages] public async Task GetAlbumIdFromName(string albumName) { var album = await DbContext.Albums.Where(a => a.Title == albumName).FirstOrDefaultAsync(); diff --git a/src/MusicStore/Areas/Admin/Views/StoreManager/Details.cshtml b/src/MusicStore/Areas/Admin/Views/StoreManager/Details.cshtml index bd342e5327..3e65c71cc6 100644 --- a/src/MusicStore/Areas/Admin/Views/StoreManager/Details.cshtml +++ b/src/MusicStore/Areas/Admin/Views/StoreManager/Details.cshtml @@ -4,61 +4,54 @@ ViewBag.Title = "Details"; } -@if (Model != null) -{ -

Details

+

Details

-
-

Album

-
-
-
- @Html.DisplayNameFor(model => model.Artist.Name) -
+
+

Album

+
+
+
+ @Html.DisplayNameFor(model => model.Artist.Name) +
-
- @Html.DisplayFor(model => model.Artist.Name) -
+
+ @Html.DisplayFor(model => model.Artist.Name) +
-
- @Html.DisplayNameFor(model => model.Genre.Name) -
+
+ @Html.DisplayNameFor(model => model.Genre.Name) +
-
- @Html.DisplayFor(model => model.Genre.Name) -
+
+ @Html.DisplayFor(model => model.Genre.Name) +
-
- @Html.DisplayNameFor(model => model.Title) -
+
+ @Html.DisplayNameFor(model => model.Title) +
-
- @Html.DisplayFor(model => model.Title) -
+
+ @Html.DisplayFor(model => model.Title) +
-
- @Html.DisplayNameFor(model => model.Price) -
+
+ @Html.DisplayNameFor(model => model.Price) +
-
- @Html.DisplayFor(model => model.Price) -
+
+ @Html.DisplayFor(model => model.Price) +
-
- @Html.DisplayNameFor(model => model.AlbumArtUrl) -
+
+ @Html.DisplayNameFor(model => model.AlbumArtUrl) +
-
- @Html.DisplayFor(model => model.AlbumArtUrl) -
+
+ @Html.DisplayFor(model => model.AlbumArtUrl) +
-
-
-} -else -{ - @Html.Label(null, "Unable to locate the album") -} +
+

@Html.ActionLink("Edit", "Edit", new { id = Model.AlbumId }) | @Html.ActionLink("Back to List", "Index") diff --git a/src/MusicStore/Areas/Admin/Views/StoreManager/Edit.cshtml b/src/MusicStore/Areas/Admin/Views/StoreManager/Edit.cshtml index 63d6b61430..3e9def0bfb 100644 --- a/src/MusicStore/Areas/Admin/Views/StoreManager/Edit.cshtml +++ b/src/MusicStore/Areas/Admin/Views/StoreManager/Edit.cshtml @@ -6,69 +6,62 @@

Edit

-@if (Model != null) +@using (Html.BeginForm()) { - @using (Html.BeginForm()) - { - @Html.AntiForgeryToken() + @Html.AntiForgeryToken() -
-

Album

-
- @Html.ValidationSummary(true) - @Html.HiddenFor(model => model.AlbumId) +
+

Album

+
+ @Html.ValidationSummary(true) + @Html.HiddenFor(model => model.AlbumId) -
- @Html.LabelFor(model => model.GenreId, "GenreId", new { @class = "control-label col-md-2" }) -
- @Html.DropDownList("GenreId", String.Empty) - @Html.ValidationMessageFor(model => model.GenreId) -
-
- -
- @Html.LabelFor(model => model.ArtistId, "ArtistId", new { @class = "control-label col-md-2" }) -
- @Html.DropDownList("ArtistId", String.Empty) - @Html.ValidationMessageFor(model => model.ArtistId) -
-
- -
- @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) -
- @Html.EditorFor(model => model.Title) - @Html.ValidationMessageFor(model => model.Title) -
-
- -
- @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" }) -
- @Html.EditorFor(model => model.Price) - @Html.ValidationMessageFor(model => model.Price) -
-
- -
- @Html.LabelFor(model => model.AlbumArtUrl, new { @class = "control-label col-md-2" }) -
- @Html.EditorFor(model => model.AlbumArtUrl) - @Html.ValidationMessageFor(model => model.AlbumArtUrl) -
-
- -
-
- -
+
+ @Html.LabelFor(model => model.GenreId, "GenreId", new { @class = "control-label col-md-2" }) +
+ @Html.DropDownList("GenreId", String.Empty) + @Html.ValidationMessageFor(model => model.GenreId)
- } -} -else -{ - @Html.Label(null, "Unable to locate the album") + +
+ @Html.LabelFor(model => model.ArtistId, "ArtistId", new { @class = "control-label col-md-2" }) +
+ @Html.DropDownList("ArtistId", String.Empty) + @Html.ValidationMessageFor(model => model.ArtistId) +
+
+ +
+ @Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" }) +
+ @Html.EditorFor(model => model.Title) + @Html.ValidationMessageFor(model => model.Title) +
+
+ +
+ @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" }) +
+ @Html.EditorFor(model => model.Price) + @Html.ValidationMessageFor(model => model.Price) +
+
+ +
+ @Html.LabelFor(model => model.AlbumArtUrl, new { @class = "control-label col-md-2" }) +
+ @Html.EditorFor(model => model.AlbumArtUrl) + @Html.ValidationMessageFor(model => model.AlbumArtUrl) +
+
+ +
+
+ +
+
+
}
diff --git a/src/MusicStore/Controllers/CheckoutController.cs b/src/MusicStore/Controllers/CheckoutController.cs index 3698d7ba64..9e547fe1e2 100644 --- a/src/MusicStore/Controllers/CheckoutController.cs +++ b/src/MusicStore/Controllers/CheckoutController.cs @@ -15,11 +15,7 @@ namespace MusicStore.Controllers private const string PromoCode = "FREE"; [FromServices] - public MusicStoreContext DbContext - { - get; - set; - } + public MusicStoreContext DbContext { get; set; } // // GET: /Checkout/ diff --git a/src/MusicStore/Controllers/HomeController.cs b/src/MusicStore/Controllers/HomeController.cs index a13bb56574..3ebb12e300 100644 --- a/src/MusicStore/Controllers/HomeController.cs +++ b/src/MusicStore/Controllers/HomeController.cs @@ -10,20 +10,11 @@ namespace MusicStore.Controllers { public class HomeController : Controller { - [FromServices] - public MusicStoreContext DbContext - { - get; - set; - } + public MusicStoreContext DbContext { get; set; } [FromServices] - public IMemoryCache Cache - { - get; - set; - } + public IMemoryCache Cache { get; set; } // // GET: /Home/ @@ -48,6 +39,11 @@ namespace MusicStore.Controllers return View("~/Views/Shared/Error.cshtml"); } + public IActionResult StatusCodePage() + { + return View("~/Views/Shared/StatusCodePage.cshtml"); + } + private async Task> GetTopSellingAlbums(int count) { // Group the order details by album and return diff --git a/src/MusicStore/Controllers/ShoppingCartController.cs b/src/MusicStore/Controllers/ShoppingCartController.cs index 24045f035d..2a7dc58733 100644 --- a/src/MusicStore/Controllers/ShoppingCartController.cs +++ b/src/MusicStore/Controllers/ShoppingCartController.cs @@ -11,11 +11,7 @@ namespace MusicStore.Controllers public class ShoppingCartController : Controller { [FromServices] - public MusicStoreContext DbContext - { - get; - set; - } + public MusicStoreContext DbContext { get; set; } // // GET: /ShoppingCart/ diff --git a/src/MusicStore/Controllers/StoreController.cs b/src/MusicStore/Controllers/StoreController.cs index 1e6d554c87..e595b8d632 100644 --- a/src/MusicStore/Controllers/StoreController.cs +++ b/src/MusicStore/Controllers/StoreController.cs @@ -10,18 +10,10 @@ namespace MusicStore.Controllers public class StoreController : Controller { [FromServices] - public MusicStoreContext DbContext - { - get; - set; - } + public MusicStoreContext DbContext { get; set; } [FromServices] - public IMemoryCache Cache - { - get; - set; - } + public IMemoryCache Cache { get; set; } // // GET: /Store/ @@ -42,6 +34,11 @@ namespace MusicStore.Controllers .Where(g => g.Name == genre) .FirstOrDefaultAsync(); + if (genreModel == null) + { + return HttpNotFound(); + } + return View(genreModel); } @@ -59,6 +56,11 @@ namespace MusicStore.Controllers .FirstOrDefaultAsync(); }); + if (album == null) + { + return HttpNotFound(); + } + return View(album); } } diff --git a/src/MusicStore/Startup.cs b/src/MusicStore/Startup.cs index 108d34f429..960de96e8e 100644 --- a/src/MusicStore/Startup.cs +++ b/src/MusicStore/Startup.cs @@ -103,6 +103,9 @@ namespace MusicStore { loggerFactory.AddConsole(); + // StatusCode pages to gracefully handle status codes 400-599. + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + //Display custom error page in production when error occurs //During development use the ErrorPage middleware to display error information in the browser app.UseErrorPage(ErrorPageOptions.ShowAll); @@ -123,6 +126,9 @@ namespace MusicStore { loggerFactory.AddConsole(); + // StatusCode pages to gracefully handle status codes 400-599. + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + app.UseErrorHandler("/Home/Error"); Configure(app); @@ -134,6 +140,9 @@ namespace MusicStore { loggerFactory.AddConsole(); + // StatusCode pages to gracefully handle status codes 400-599. + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + app.UseErrorHandler("/Home/Error"); Configure(app); diff --git a/src/MusicStore/StartupNtlmAuthentication.cs b/src/MusicStore/StartupNtlmAuthentication.cs index d80ed2b670..55760e1f82 100644 --- a/src/MusicStore/StartupNtlmAuthentication.cs +++ b/src/MusicStore/StartupNtlmAuthentication.cs @@ -73,6 +73,12 @@ namespace MusicStore { loggerFactory.AddConsole(); + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + + //Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline. + //Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production. + app.UseErrorPage(ErrorPageOptions.ShowAll); + //Set up NTLM authentication for WebListener like below. //For IIS and IISExpress: Use inetmgr to setup NTLM authentication on the application vDir or modify the applicationHost.config to enable NTLM. if ((app.Server as ServerInformation) != null) @@ -81,10 +87,6 @@ namespace MusicStore serverInformation.Listener.AuthenticationManager.AuthenticationTypes = AuthenticationTypes.NTLM; } - //Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline. - //Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production. - app.UseErrorPage(ErrorPageOptions.ShowAll); - app.UseDatabaseErrorPage(DatabaseErrorPageOptions.ShowAll); // Add the runtime information page that can be used by developers diff --git a/src/MusicStore/StartupOpenIdConnect.cs b/src/MusicStore/StartupOpenIdConnect.cs index a6d98a3829..2955fefad5 100644 --- a/src/MusicStore/StartupOpenIdConnect.cs +++ b/src/MusicStore/StartupOpenIdConnect.cs @@ -89,6 +89,8 @@ namespace MusicStore { loggerFactory.AddConsole(); + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + //Display custom error page in production when error occurs //During development use the ErrorPage middleware to display error information in the browser app.UseErrorPage(ErrorPageOptions.ShowAll); diff --git a/src/MusicStore/Views/Shared/StatusCodePage.cshtml b/src/MusicStore/Views/Shared/StatusCodePage.cshtml new file mode 100644 index 0000000000..53dff8781a --- /dev/null +++ b/src/MusicStore/Views/Shared/StatusCodePage.cshtml @@ -0,0 +1,6 @@ +@{ + ViewBag.Title = "Item not found"; +} + +

Item not found.

+

Unable to find the item you are searching for. Please try again.

\ No newline at end of file diff --git a/test/E2ETests/Implementation/Scenarios.cs b/test/E2ETests/Implementation/Scenarios.cs index 2ee71408e0..8f47fa8474 100644 --- a/test/E2ETests/Implementation/Scenarios.cs +++ b/test/E2ETests/Implementation/Scenarios.cs @@ -354,6 +354,16 @@ namespace E2ETests Assert.Contains(PrefixBaseAddress("Back to List"), responseContent, StringComparison.OrdinalIgnoreCase); } + private void VerifyStatusCodePages() + { + _logger.WriteInformation("Getting details of a non-existing album with Id '-1'"); + var response = _httpClient.GetAsync("Admin/StoreManager/Details?id=-1").Result; + ThrowIfResponseStatusNotOk(response); + var responseContent = response.Content.ReadAsStringAsync().Result; + Assert.Contains("Item not found.", responseContent, StringComparison.OrdinalIgnoreCase); + Assert.Equal(PrefixBaseAddress("/{0}/Home/StatusCodePage"), response.RequestMessage.RequestUri.AbsolutePath); + } + // This gets the view that non-admin users get to see. private void GetAlbumDetailsFromStore(string albumId, string albumName) { diff --git a/test/E2ETests/SmokeTests.cs b/test/E2ETests/SmokeTests.cs index 0f5ca21e15..ae3412cc08 100644 --- a/test/E2ETests/SmokeTests.cs +++ b/test/E2ETests/SmokeTests.cs @@ -196,6 +196,9 @@ namespace E2ETests //Get details of the album VerifyAlbumDetails(albumId, albumName); + //Verify status code pages acts on non-existing items. + VerifyStatusCodePages(); + //Get the non-admin view of the album. GetAlbumDetailsFromStore(albumId, albumName); diff --git a/test/E2ETests/compiler/shared/Mocks/StartupOpenIdConnectTesting.cs b/test/E2ETests/compiler/shared/Mocks/StartupOpenIdConnectTesting.cs index 34234b10b3..7b5106ff05 100644 --- a/test/E2ETests/compiler/shared/Mocks/StartupOpenIdConnectTesting.cs +++ b/test/E2ETests/compiler/shared/Mocks/StartupOpenIdConnectTesting.cs @@ -79,6 +79,8 @@ namespace MusicStore { loggerFactory.AddConsole(); + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + //Display custom error page in production when error occurs //During development use the ErrorPage middleware to display error information in the browser app.UseErrorPage(ErrorPageOptions.ShowAll); diff --git a/test/E2ETests/compiler/shared/Mocks/StartupSocialTesting.cs b/test/E2ETests/compiler/shared/Mocks/StartupSocialTesting.cs index da32e6f91a..eaf0708a7a 100644 --- a/test/E2ETests/compiler/shared/Mocks/StartupSocialTesting.cs +++ b/test/E2ETests/compiler/shared/Mocks/StartupSocialTesting.cs @@ -115,6 +115,8 @@ namespace MusicStore { loggerFactory.AddConsole(); + app.UseStatusCodePagesWithRedirects("~/Home/StatusCodePage"); + //Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline. //Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production. app.UseErrorPage(ErrorPageOptions.ShowAll);