Add solution code for Exercise 15.2

This commit is contained in:
Mark J Price 2023-06-08 11:08:01 +01:00
parent 69ad593b07
commit f68d88588e
12 changed files with 462 additions and 18 deletions

View file

@ -135,7 +135,7 @@ namespace Northwind.Mvc.Controllers
return View(model); // pass model to view
}
public async Task<IActionResult> Customers(string country)
public async Task<IActionResult> Customers(string? country = null)
{
string uri;
@ -161,12 +161,92 @@ namespace Northwind.Mvc.Controllers
IEnumerable<Customer>? model = await response.Content
.ReadFromJsonAsync<IEnumerable<Customer>>();
if (model is not null)
{
model = model.OrderBy(c => c.CustomerId);
}
return View(model);
}
// Matches /home/categorydetail/{id} by default so to
// match /category/{id}, decorate with the following:
// [Route("category/{id}")]
// GET /Home/AddCustomer
public IActionResult AddCustomer()
{
ViewData["Title"] = "Add Customer";
return View();
}
// POST /Home/AddCustomer
// A Customer object in the request body.
[HttpPost]
public async Task<IActionResult> AddCustomer(Customer customer)
{
HttpClient client = clientFactory.CreateClient(
name: "Northwind.WebApi");
HttpResponseMessage response = await client.PostAsJsonAsync(
requestUri: "api/customers", value: customer);
// Optionally, get the created customer back as JSON
// so the user can see the assigned ID, for example.
Customer? model = await response.Content
.ReadFromJsonAsync<Customer>();
if (response.IsSuccessStatusCode)
{
TempData["success-message"] = "Customer successfully added.";
}
else
{
TempData["error-message"] = "Customer was NOT added.";
}
// Show the full customers list to see if it was added.
return RedirectToAction("Customers");
}
// GET /Home/DeleteCustomer
public async Task<IActionResult> DeleteCustomer(string customerId)
{
HttpClient client = clientFactory.CreateClient(
name: "Northwind.WebApi");
Customer? customer = await client.GetFromJsonAsync<Customer>(
requestUri: $"api/customers/{customerId}");
ViewData["Title"] = "Delete Customer";
return View(customer);
}
// POST /Home/DeleteCustomer
// A CustomerId in the request body e.g. ALFKI.
[HttpPost]
[Route("home/deletecustomer")]
// Action method name must have a different name from the GET method
// due to C# not allowing duplicate method signatures.
public async Task<IActionResult> DeleteCustomerPost(string customerId)
{
HttpClient client = clientFactory.CreateClient(
name: "Northwind.WebApi");
HttpResponseMessage response = await client.DeleteAsync(
requestUri: $"api/customers/{customerId}");
if (response.IsSuccessStatusCode)
{
TempData["success-message"] = "Customer successfully deleted.";
}
else
{
TempData["error-message"] = $"Customer {customerId} was NOT deleted.";
}
// Show the full customers list to see if it was deleted.
return RedirectToAction("Customers");
}
[Route("category/{id}")]
public async Task<IActionResult> CategoryDetail(int? id)
{
if (!id.HasValue)

View file

@ -92,8 +92,8 @@ app.UseOutputCache();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
.CacheOutput("views");
pattern: "{controller=Home}/{action=Index}/{id?}");
// .CacheOutput("views");
app.MapRazorPages();

View file

@ -0,0 +1,68 @@
@using Packt.Shared
@model Customer
<h2>@ViewData["Title"]</h2>
<!--
Show an editable form with a blank customer. Postback to the action
method AddCustomer to perform the actual insert.
-->
<form asp-action="AddCustomer" method="post">
<div class="mb-3">
<label class="form-label" for="customerId">Customer ID</label>
@Html.EditorFor(model => model.CustomerId,
new { htmlAttributes = new { @class = "form-control" } })
<div class="form-text">
Customer ID must be five (5) upper case characters.
</div>
</div>
<div class="mb-3">
<label class="form-label" for="companyName">Company Name</label>
@Html.EditorFor(model => model.CompanyName,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="contactName">Contact Name</label>
@Html.EditorFor(model => model.ContactName,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="address">Address</label>
@Html.EditorFor(model => model.Address,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="city">City</label>
@Html.EditorFor(model => model.City,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="region">Region</label>
@Html.EditorFor(model => model.Region,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="country">Country</label>
@Html.EditorFor(model => model.Country,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="postalCode">Postal Code</label>
@Html.EditorFor(model => model.PostalCode,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="phone">Phone</label>
@Html.EditorFor(model => model.Phone,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<input type="submit" value="Add Customer"
class="btn btn-outline-primary" />
<a asp-controller="Home" asp-action="Customers"
class="btn btn-outline-secondary">
Cancel and return to Customers
</a>
@Html.ValidationSummary()
</div>
</form>

View file

@ -2,6 +2,19 @@
@model IEnumerable<Customer>
<h2>@ViewData["Title"]</h2>
@if (TempData["error-message"] is not null)
{
<p class="alert alert-danger">Error! @TempData["error-message"]</p>
}
@if (TempData["success-message"] is not null)
{
<p class="alert alert-success">Congratulations! @TempData["success-message"]</p>
}
<a asp-controller="Home" asp-action="AddCustomer"
class="btn btn-outline-primary">Add Customer</a>
<table class="table">
<thead>
<tr>
@ -9,6 +22,7 @@
<th>Contact Name</th>
<th>Address</th>
<th>Phone</th>
<th></th>
</tr>
</thead>
<tbody>
@ -33,6 +47,12 @@
<td>
@Html.DisplayFor(modelItem => c.Phone)
</td>
<td>
<a asp-controller="Home"
asp-action="DeleteCustomer"
asp-route-customerid="@c.CustomerId"
class="btn btn-outline-danger">Delete</a>
</td>
</tr>
}
}

View file

@ -0,0 +1,54 @@
@using Packt.Shared
@model Customer
<h2>@ViewData["Title"]</h2>
<!--
Show a readonly form of an existing customer. Postback to the action
method DeleteCustomer to perform the actual delete.
-->
<form asp-action="DeleteCustomer" method="post">
<div class="mb-3">
<label class="form-label" for="customerId">Customer ID</label>
<input class="form-control" id="customerId" value="@Model.CustomerId" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="companyName">Company Name</label>
<input class="form-control" id="companyName" value="@Model.CompanyName" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="contactName">Contact Name</label>
<input class="form-control" id="contactName" value="@Model.ContactName" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="address">Address</label>
<input class="form-control" id="address" value="@Model.Address" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="city">City</label>
<input class="form-control" id="city" value="@Model.City" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="region">Region</label>
<input class="form-control" id="region" value="@Model.Region" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="country">Country</label>
<input class="form-control" id="country" value="@Model.Country" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="postalCode">Postal Code</label>
<input class="form-control" id="postalCode" value="@Model.PostalCode" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="phone">Phone</label>
<input class="form-control" id="phone" value="@Model.Phone" readonly />
</div>
<div class="mb-3">
@Html.HiddenFor(c => c.CustomerId)
<input type="submit" value="Delete Customer"
class="btn btn-outline-danger" />
<a href="customers" class="btn btn-outline-secondary">
Cancel and return to Customers
</a>
</div>
</form>

View file

@ -69,7 +69,7 @@
<h3>@Model.Categories[c].Description</h3>
<p>
<a class="btn btn-primary"
href="/home/categorydetail/@Model.Categories[c].CategoryId">View</a>
href="/category/@Model.Categories[c].CategoryId">View</a>
</p>
</div>
</div>

View file

@ -135,7 +135,7 @@ namespace Northwind.Mvc.Controllers
return View(model); // pass model to view
}
public async Task<IActionResult> Customers(string country)
public async Task<IActionResult> Customers(string? country = null)
{
string uri;
@ -161,12 +161,92 @@ namespace Northwind.Mvc.Controllers
IEnumerable<Customer>? model = await response.Content
.ReadFromJsonAsync<IEnumerable<Customer>>();
if (model is not null)
{
model = model.OrderBy(c => c.CustomerId);
}
return View(model);
}
// Matches /home/categorydetail/{id} by default so to
// match /category/{id}, decorate with the following:
// [Route("category/{id}")]
// GET /Home/AddCustomer
public IActionResult AddCustomer()
{
ViewData["Title"] = "Add Customer";
return View();
}
// POST /Home/AddCustomer
// A Customer object in the request body.
[HttpPost]
public async Task<IActionResult> AddCustomer(Customer customer)
{
HttpClient client = clientFactory.CreateClient(
name: "Northwind.WebApi");
HttpResponseMessage response = await client.PostAsJsonAsync(
requestUri: "api/customers", value: customer);
// Optionally, get the created customer back as JSON
// so the user can see the assigned ID, for example.
Customer? model = await response.Content
.ReadFromJsonAsync<Customer>();
if (response.IsSuccessStatusCode)
{
TempData["success-message"] = "Customer successfully added.";
}
else
{
TempData["error-message"] = "Customer was NOT added.";
}
// Show the full customers list to see if it was added.
return RedirectToAction("Customers");
}
// GET /Home/DeleteCustomer
public async Task<IActionResult> DeleteCustomer(string customerId)
{
HttpClient client = clientFactory.CreateClient(
name: "Northwind.WebApi");
Customer? customer = await client.GetFromJsonAsync<Customer>(
requestUri: $"api/customers/{customerId}");
ViewData["Title"] = "Delete Customer";
return View(customer);
}
// POST /Home/DeleteCustomer
// A CustomerId in the request body e.g. ALFKI.
[HttpPost]
[Route("home/deletecustomer")]
// Action method name must have a different name from the GET method
// due to C# not allowing duplicate method signatures.
public async Task<IActionResult> DeleteCustomerPost(string customerId)
{
HttpClient client = clientFactory.CreateClient(
name: "Northwind.WebApi");
HttpResponseMessage response = await client.DeleteAsync(
requestUri: $"api/customers/{customerId}");
if (response.IsSuccessStatusCode)
{
TempData["success-message"] = "Customer successfully deleted.";
}
else
{
TempData["error-message"] = $"Customer {customerId} was NOT deleted.";
}
// Show the full customers list to see if it was deleted.
return RedirectToAction("Customers");
}
[Route("category/{id}")]
public async Task<IActionResult> CategoryDetail(int? id)
{
if (!id.HasValue)

View file

@ -92,8 +92,8 @@ app.UseOutputCache();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}")
.CacheOutput("views");
pattern: "{controller=Home}/{action=Index}/{id?}");
// .CacheOutput("views");
app.MapRazorPages();

View file

@ -0,0 +1,68 @@
@using Packt.Shared
@model Customer
<h2>@ViewData["Title"]</h2>
<!--
Show an editable form with a blank customer. Postback to the action
method AddCustomer to perform the actual insert.
-->
<form asp-action="AddCustomer" method="post">
<div class="mb-3">
<label class="form-label" for="customerId">Customer ID</label>
@Html.EditorFor(model => model.CustomerId,
new { htmlAttributes = new { @class = "form-control" } })
<div class="form-text">
Customer ID must be five (5) upper case characters.
</div>
</div>
<div class="mb-3">
<label class="form-label" for="companyName">Company Name</label>
@Html.EditorFor(model => model.CompanyName,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="contactName">Contact Name</label>
@Html.EditorFor(model => model.ContactName,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="address">Address</label>
@Html.EditorFor(model => model.Address,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="city">City</label>
@Html.EditorFor(model => model.City,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="region">Region</label>
@Html.EditorFor(model => model.Region,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="country">Country</label>
@Html.EditorFor(model => model.Country,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="postalCode">Postal Code</label>
@Html.EditorFor(model => model.PostalCode,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<label class="form-label" for="phone">Phone</label>
@Html.EditorFor(model => model.Phone,
new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="mb-3">
<input type="submit" value="Add Customer"
class="btn btn-outline-primary" />
<a asp-controller="Home" asp-action="Customers"
class="btn btn-outline-secondary">
Cancel and return to Customers
</a>
@Html.ValidationSummary()
</div>
</form>

View file

@ -2,6 +2,19 @@
@model IEnumerable<Customer>
<h2>@ViewData["Title"]</h2>
@if (TempData["error-message"] is not null)
{
<p class="alert alert-danger">Error! @TempData["error-message"]</p>
}
@if (TempData["success-message"] is not null)
{
<p class="alert alert-success">Congratulations! @TempData["success-message"]</p>
}
<a asp-controller="Home" asp-action="AddCustomer"
class="btn btn-outline-primary">Add Customer</a>
<table class="table">
<thead>
<tr>
@ -9,6 +22,7 @@
<th>Contact Name</th>
<th>Address</th>
<th>Phone</th>
<th></th>
</tr>
</thead>
<tbody>
@ -33,6 +47,12 @@
<td>
@Html.DisplayFor(modelItem => c.Phone)
</td>
<td>
<a asp-controller="Home"
asp-action="DeleteCustomer"
asp-route-customerid="@c.CustomerId"
class="btn btn-outline-danger">Delete</a>
</td>
</tr>
}
}

View file

@ -0,0 +1,54 @@
@using Packt.Shared
@model Customer
<h2>@ViewData["Title"]</h2>
<!--
Show a readonly form of an existing customer. Postback to the action
method DeleteCustomer to perform the actual delete.
-->
<form asp-action="DeleteCustomer" method="post">
<div class="mb-3">
<label class="form-label" for="customerId">Customer ID</label>
<input class="form-control" id="customerId" value="@Model.CustomerId" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="companyName">Company Name</label>
<input class="form-control" id="companyName" value="@Model.CompanyName" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="contactName">Contact Name</label>
<input class="form-control" id="contactName" value="@Model.ContactName" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="address">Address</label>
<input class="form-control" id="address" value="@Model.Address" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="city">City</label>
<input class="form-control" id="city" value="@Model.City" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="region">Region</label>
<input class="form-control" id="region" value="@Model.Region" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="country">Country</label>
<input class="form-control" id="country" value="@Model.Country" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="postalCode">Postal Code</label>
<input class="form-control" id="postalCode" value="@Model.PostalCode" readonly />
</div>
<div class="mb-3">
<label class="form-label" for="phone">Phone</label>
<input class="form-control" id="phone" value="@Model.Phone" readonly />
</div>
<div class="mb-3">
@Html.HiddenFor(c => c.CustomerId)
<input type="submit" value="Delete Customer"
class="btn btn-outline-danger" />
<a href="customers" class="btn btn-outline-secondary">
Cancel and return to Customers
</a>
</div>
</form>

View file

@ -69,7 +69,7 @@
<h3>@Model.Categories[c].Description</h3>
<p>
<a class="btn btn-primary"
href="/home/categorydetail/@Model.Categories[c].CategoryId">View</a>
href="/category/@Model.Categories[c].CategoryId">View</a>
</p>
</div>
</div>