Using statuscode pages in the sample

Adding some automation as well.
This commit is contained in:
Praburaj 2015-02-16 17:18:12 -08:00
parent af58d878ba
commit 7da407a17a
15 changed files with 166 additions and 157 deletions

View File

@ -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();

View File

@ -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")

View File

@ -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>

View File

@ -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/

View File

@ -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

View File

@ -11,11 +11,7 @@ namespace MusicStore.Controllers
public class ShoppingCartController : Controller
{
[FromServices]
public MusicStoreContext DbContext
{
get;
set;
}
public MusicStoreContext DbContext { get; set; }
//
// GET: /ShoppingCart/

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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>

View File

@ -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)
{

View File

@ -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);

View File

@ -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);

View File

@ -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);