Using statuscode pages in the sample
Adding some automation as well.
This commit is contained in:
parent
af58d878ba
commit
7da407a17a
|
|
@ -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<IActionResult> 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<IActionResult> 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<IActionResult> GetAlbumIdFromName(string albumName)
|
||||
{
|
||||
var album = await DbContext.Albums.Where(a => a.Title == albumName).FirstOrDefaultAsync();
|
||||
|
|
|
|||
|
|
@ -4,61 +4,54 @@
|
|||
ViewBag.Title = "Details";
|
||||
}
|
||||
|
||||
@if (Model != null)
|
||||
{
|
||||
<h2>Details</h2>
|
||||
<h2>Details</h2>
|
||||
|
||||
<div>
|
||||
<h4>Album</h4>
|
||||
<hr />
|
||||
<dl class="dl-horizontal">
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Artist.Name)
|
||||
</dt>
|
||||
<div>
|
||||
<h4>Album</h4>
|
||||
<hr />
|
||||
<dl class="dl-horizontal">
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Artist.Name)
|
||||
</dt>
|
||||
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Artist.Name)
|
||||
</dd>
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Artist.Name)
|
||||
</dd>
|
||||
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Genre.Name)
|
||||
</dt>
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Genre.Name)
|
||||
</dt>
|
||||
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Genre.Name)
|
||||
</dd>
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Genre.Name)
|
||||
</dd>
|
||||
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Title)
|
||||
</dt>
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Title)
|
||||
</dt>
|
||||
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Title)
|
||||
</dd>
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Title)
|
||||
</dd>
|
||||
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Price)
|
||||
</dt>
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.Price)
|
||||
</dt>
|
||||
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Price)
|
||||
</dd>
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.Price)
|
||||
</dd>
|
||||
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.AlbumArtUrl)
|
||||
</dt>
|
||||
<dt>
|
||||
@Html.DisplayNameFor(model => model.AlbumArtUrl)
|
||||
</dt>
|
||||
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.AlbumArtUrl)
|
||||
</dd>
|
||||
<dd>
|
||||
@Html.DisplayFor(model => model.AlbumArtUrl)
|
||||
</dd>
|
||||
|
||||
</dl>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Html.Label(null, "Unable to locate the album")
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
<p>
|
||||
@Html.ActionLink("Edit", "Edit", new { id = Model.AlbumId }) |
|
||||
@Html.ActionLink("Back to List", "Index")
|
||||
|
|
|
|||
|
|
@ -6,69 +6,62 @@
|
|||
|
||||
<h2>Edit</h2>
|
||||
|
||||
@if (Model != null)
|
||||
@using (Html.BeginForm())
|
||||
{
|
||||
@using (Html.BeginForm())
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
<div class="form-horizontal">
|
||||
<h4>Album</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary(true)
|
||||
@Html.HiddenFor(model => model.AlbumId)
|
||||
<div class="form-horizontal">
|
||||
<h4>Album</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary(true)
|
||||
@Html.HiddenFor(model => model.AlbumId)
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.GenreId, "GenreId", new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.DropDownList("GenreId", String.Empty)
|
||||
@Html.ValidationMessageFor(model => model.GenreId)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.ArtistId, "ArtistId", new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.DropDownList("ArtistId", String.Empty)
|
||||
@Html.ValidationMessageFor(model => model.ArtistId)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.EditorFor(model => model.Title)
|
||||
@Html.ValidationMessageFor(model => model.Title)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.EditorFor(model => model.Price)
|
||||
@Html.ValidationMessageFor(model => model.Price)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.AlbumArtUrl, new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.EditorFor(model => model.AlbumArtUrl)
|
||||
@Html.ValidationMessageFor(model => model.AlbumArtUrl)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Save" class="btn btn-default" />
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.GenreId, "GenreId", new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.DropDownList("GenreId", String.Empty)
|
||||
@Html.ValidationMessageFor(model => model.GenreId)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@Html.Label(null, "Unable to locate the album")
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.ArtistId, "ArtistId", new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.DropDownList("ArtistId", String.Empty)
|
||||
@Html.ValidationMessageFor(model => model.ArtistId)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.Title, new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.EditorFor(model => model.Title)
|
||||
@Html.ValidationMessageFor(model => model.Title)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.EditorFor(model => model.Price)
|
||||
@Html.ValidationMessageFor(model => model.Price)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(model => model.AlbumArtUrl, new { @class = "control-label col-md-2" })
|
||||
<div class="col-md-10">
|
||||
@Html.EditorFor(model => model.AlbumArtUrl)
|
||||
@Html.ValidationMessageFor(model => model.AlbumArtUrl)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Save" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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<List<Album>> GetTopSellingAlbums(int count)
|
||||
{
|
||||
// Group the order details by album and return
|
||||
|
|
|
|||
|
|
@ -11,11 +11,7 @@ namespace MusicStore.Controllers
|
|||
public class ShoppingCartController : Controller
|
||||
{
|
||||
[FromServices]
|
||||
public MusicStoreContext DbContext
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
public MusicStoreContext DbContext { get; set; }
|
||||
|
||||
//
|
||||
// GET: /ShoppingCart/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
@{
|
||||
ViewBag.Title = "Item not found";
|
||||
}
|
||||
|
||||
<h1 class="text-danger">Item not found.</h1>
|
||||
<h2 class="text-danger">Unable to find the item you are searching for. Please try again.</h2>
|
||||
|
|
@ -354,6 +354,16 @@ namespace E2ETests
|
|||
Assert.Contains(PrefixBaseAddress("<a href=\"/{0}/Admin/StoreManager\">Back to List</a>"), 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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue