diff --git a/vs4win/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs b/vs4win/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs index cac8de0..3ee5c38 100644 --- a/vs4win/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs +++ b/vs4win/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs @@ -135,7 +135,7 @@ namespace Northwind.Mvc.Controllers return View(model); // pass model to view } - public async Task Customers(string country) + public async Task Customers(string? country = null) { string uri; @@ -161,12 +161,92 @@ namespace Northwind.Mvc.Controllers IEnumerable? model = await response.Content .ReadFromJsonAsync>(); + 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 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(); + + 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 DeleteCustomer(string customerId) + { + HttpClient client = clientFactory.CreateClient( + name: "Northwind.WebApi"); + + Customer? customer = await client.GetFromJsonAsync( + 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 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 CategoryDetail(int? id) { if (!id.HasValue) diff --git a/vs4win/PracticalApps/Northwind.Mvc/Program.cs b/vs4win/PracticalApps/Northwind.Mvc/Program.cs index b1dc93a..39144f1 100644 --- a/vs4win/PracticalApps/Northwind.Mvc/Program.cs +++ b/vs4win/PracticalApps/Northwind.Mvc/Program.cs @@ -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(); diff --git a/vs4win/PracticalApps/Northwind.Mvc/Views/Home/AddCustomer.cshtml b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/AddCustomer.cshtml new file mode 100644 index 0000000..2308561 --- /dev/null +++ b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/AddCustomer.cshtml @@ -0,0 +1,68 @@ +@using Packt.Shared +@model Customer + +

@ViewData["Title"]

+ + +
+
+ + @Html.EditorFor(model => model.CustomerId, + new { htmlAttributes = new { @class = "form-control" } }) +
+ Customer ID must be five (5) upper case characters. +
+
+
+ + @Html.EditorFor(model => model.CompanyName, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.ContactName, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Address, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.City, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Region, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Country, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.PostalCode, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Phone, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + + Cancel and return to Customers + + @Html.ValidationSummary() +
+
diff --git a/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml index 42b464f..a4d6847 100644 --- a/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml +++ b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml @@ -2,6 +2,19 @@ @model IEnumerable

@ViewData["Title"]

+ +@if (TempData["error-message"] is not null) +{ +

Error! @TempData["error-message"]

+} +@if (TempData["success-message"] is not null) +{ +

Congratulations! @TempData["success-message"]

+} + +Add Customer + @@ -9,6 +22,7 @@ + @@ -24,15 +38,21 @@ @Html.DisplayFor(modelItem => c.ContactName) + } } diff --git a/vs4win/PracticalApps/Northwind.Mvc/Views/Home/DeleteCustomer.cshtml b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/DeleteCustomer.cshtml new file mode 100644 index 0000000..db392b6 --- /dev/null +++ b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/DeleteCustomer.cshtml @@ -0,0 +1,54 @@ +@using Packt.Shared +@model Customer +

@ViewData["Title"]

+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ @Html.HiddenFor(c => c.CustomerId) + + + Cancel and return to Customers + +
+ diff --git a/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml index 45ded79..0f88e7d 100644 --- a/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml +++ b/vs4win/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml @@ -69,7 +69,7 @@

@Model.Categories[c].Description

View + href="/category/@Model.Categories[c].CategoryId">View

diff --git a/vscode/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs b/vscode/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs index cac8de0..3ee5c38 100644 --- a/vscode/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs +++ b/vscode/PracticalApps/Northwind.Mvc/Controllers/HomeController.cs @@ -135,7 +135,7 @@ namespace Northwind.Mvc.Controllers return View(model); // pass model to view } - public async Task Customers(string country) + public async Task Customers(string? country = null) { string uri; @@ -161,12 +161,92 @@ namespace Northwind.Mvc.Controllers IEnumerable? model = await response.Content .ReadFromJsonAsync>(); + 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 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(); + + 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 DeleteCustomer(string customerId) + { + HttpClient client = clientFactory.CreateClient( + name: "Northwind.WebApi"); + + Customer? customer = await client.GetFromJsonAsync( + 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 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 CategoryDetail(int? id) { if (!id.HasValue) diff --git a/vscode/PracticalApps/Northwind.Mvc/Program.cs b/vscode/PracticalApps/Northwind.Mvc/Program.cs index b1dc93a..39144f1 100644 --- a/vscode/PracticalApps/Northwind.Mvc/Program.cs +++ b/vscode/PracticalApps/Northwind.Mvc/Program.cs @@ -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(); diff --git a/vscode/PracticalApps/Northwind.Mvc/Views/Home/AddCustomer.cshtml b/vscode/PracticalApps/Northwind.Mvc/Views/Home/AddCustomer.cshtml new file mode 100644 index 0000000..2308561 --- /dev/null +++ b/vscode/PracticalApps/Northwind.Mvc/Views/Home/AddCustomer.cshtml @@ -0,0 +1,68 @@ +@using Packt.Shared +@model Customer + +

@ViewData["Title"]

+ + +
+
+ + @Html.EditorFor(model => model.CustomerId, + new { htmlAttributes = new { @class = "form-control" } }) +
+ Customer ID must be five (5) upper case characters. +
+
+
+ + @Html.EditorFor(model => model.CompanyName, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.ContactName, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Address, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.City, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Region, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Country, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.PostalCode, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + @Html.EditorFor(model => model.Phone, + new { htmlAttributes = new { @class = "form-control" } }) +
+
+ + + Cancel and return to Customers + + @Html.ValidationSummary() +
+ diff --git a/vscode/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml b/vscode/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml index 42b464f..a4d6847 100644 --- a/vscode/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml +++ b/vscode/PracticalApps/Northwind.Mvc/Views/Home/Customers.cshtml @@ -2,6 +2,19 @@ @model IEnumerable

@ViewData["Title"]

+ +@if (TempData["error-message"] is not null) +{ +

Error! @TempData["error-message"]

+} +@if (TempData["success-message"] is not null) +{ +

Congratulations! @TempData["success-message"]

+} + +Add Customer +
Contact Name Address Phone
- @Html.DisplayFor(modelItem => c.Address) + @Html.DisplayFor(modelItem => c.Address) @Html.DisplayFor(modelItem => c.City) @Html.DisplayFor(modelItem => c.Region) - @Html.DisplayFor(modelItem => c.Country) + @Html.DisplayFor(modelItem => c.Country) @Html.DisplayFor(modelItem => c.PostalCode) @Html.DisplayFor(modelItem => c.Phone) + Delete +
@@ -9,6 +22,7 @@ + @@ -24,15 +38,21 @@ @Html.DisplayFor(modelItem => c.ContactName) + } } diff --git a/vscode/PracticalApps/Northwind.Mvc/Views/Home/DeleteCustomer.cshtml b/vscode/PracticalApps/Northwind.Mvc/Views/Home/DeleteCustomer.cshtml new file mode 100644 index 0000000..db392b6 --- /dev/null +++ b/vscode/PracticalApps/Northwind.Mvc/Views/Home/DeleteCustomer.cshtml @@ -0,0 +1,54 @@ +@using Packt.Shared +@model Customer +

@ViewData["Title"]

+ + + +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ @Html.HiddenFor(c => c.CustomerId) + + + Cancel and return to Customers + +
+ diff --git a/vscode/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml b/vscode/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml index 45ded79..0f88e7d 100644 --- a/vscode/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml +++ b/vscode/PracticalApps/Northwind.Mvc/Views/Home/Index.cshtml @@ -69,7 +69,7 @@

@Model.Categories[c].Description

View + href="/category/@Model.Categories[c].CategoryId">View

Contact Name Address Phone
- @Html.DisplayFor(modelItem => c.Address) + @Html.DisplayFor(modelItem => c.Address) @Html.DisplayFor(modelItem => c.City) @Html.DisplayFor(modelItem => c.Region) - @Html.DisplayFor(modelItem => c.Country) + @Html.DisplayFor(modelItem => c.Country) @Html.DisplayFor(modelItem => c.PostalCode) @Html.DisplayFor(modelItem => c.Phone) + Delete +