From 47fe289c741a5e54340cdec78fdbc9918f7bdcdc Mon Sep 17 00:00:00 2001 From: gorohoroh Date: Wed, 4 Jul 2018 17:07:46 +0300 Subject: [PATCH] Creating new services: IRestaurantData, InMemoryRestaurantData, registering one of them in Startup.cs, modifying the Home controller to receive restaurant data from an IRestaurantData service, updating the view to accept an enumerable model and iterate through the collection of restaurants --- .../Controllers/HomeController.cs | 13 ++++++-- .../Services/IRestaurantData.cs | 11 +++++++ .../Services/InMemoryRestaurantData.cs | 32 +++++++++++++++++++ OdeToFoodRider/OdeToFoodRider/Startup.cs | 1 + .../OdeToFoodRider/Views/Home/Index.cshtml | 17 ++++++++-- .../Controllers/HomeController.cs | 15 ++++++++- .../Services/IRestaurantData.cs | 13 ++++++++ .../Services/InMemoryRestaurantData.cs | 32 +++++++++++++++++++ .../OdeToFoodVisualStudio/Startup.cs | 3 +- .../Views/Home/Index.cshtml | 16 +++++++--- 10 files changed, 142 insertions(+), 11 deletions(-) create mode 100644 OdeToFoodRider/OdeToFoodRider/Services/IRestaurantData.cs create mode 100644 OdeToFoodRider/OdeToFoodRider/Services/InMemoryRestaurantData.cs create mode 100644 OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/IRestaurantData.cs create mode 100644 OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/InMemoryRestaurantData.cs diff --git a/OdeToFoodRider/OdeToFoodRider/Controllers/HomeController.cs b/OdeToFoodRider/OdeToFoodRider/Controllers/HomeController.cs index 4e970f3..d9619e9 100644 --- a/OdeToFoodRider/OdeToFoodRider/Controllers/HomeController.cs +++ b/OdeToFoodRider/OdeToFoodRider/Controllers/HomeController.cs @@ -1,14 +1,23 @@ using Microsoft.AspNetCore.Mvc; using OdeToFoodRider.Models; +using OdeToFoodRider.Services; namespace OdeToFoodRider.Controllers { public class HomeController : Controller { + // VSRD: This time, "Initialize field from constructor" does exactly what we want. + IRestaurantData _restaurantData; + + public HomeController(IRestaurantData restaurantData) + { + _restaurantData = restaurantData; + } + + public IActionResult Index() { - var model = new Restaurant() {Id = 1, Name = "Scott's Pizza Place"}; - + var model = _restaurantData.GetAll(); return View(model); } } diff --git a/OdeToFoodRider/OdeToFoodRider/Services/IRestaurantData.cs b/OdeToFoodRider/OdeToFoodRider/Services/IRestaurantData.cs new file mode 100644 index 0000000..e202e59 --- /dev/null +++ b/OdeToFoodRider/OdeToFoodRider/Services/IRestaurantData.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using OdeToFoodRider.Models; + +namespace OdeToFoodRider.Services +{ + public interface IRestaurantData + { + // VSRD: Complete Statement at GetAll{caret} generates both the parentheses and the semicolon + IEnumerable GetAll(); + } +} \ No newline at end of file diff --git a/OdeToFoodRider/OdeToFoodRider/Services/InMemoryRestaurantData.cs b/OdeToFoodRider/OdeToFoodRider/Services/InMemoryRestaurantData.cs new file mode 100644 index 0000000..cb6f23c --- /dev/null +++ b/OdeToFoodRider/OdeToFoodRider/Services/InMemoryRestaurantData.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Linq; +using OdeToFoodRider.Models; + +namespace OdeToFoodRider.Services +{ + class InMemoryRestaurantData : IRestaurantData + { + // VSRD: Quick-fix "Initialize field from constructor" is available after declaring the _restaurants field. + // However, the created constructor takes a list of restaurants as a parameter; what we need instead is a parameterless constructor + // with a field inside that is initialized with a new list. No context action or refactoring to convert parameter to + // field initialization, and Change Signature doesn't do that, too. No big deal to do this by hand though. + private List _restaurants; + + public InMemoryRestaurantData() + { + _restaurants = new List + { + // VSRD: Rider's code completion after "new" results in "new Restaurant()", where parentheses become redundant once braces are added for initializing properties. + // A typing assistant that removes redundant parentheses wouldn't hurt here. + new Restaurant {Id = 1, Name = "Scott's Pizza Place"}, // VSRD: Rider's Complete Statement here doesn't add a comma either but instead, moves the caret beyond the scope of the collection initializer - looks like a bug + new Restaurant() {Id = 2, Name = "Tersiguels"}, + new Restaurant() {Id = 3, Name = "King's Contrivance"} + }; + } + + public IEnumerable GetAll() + { + return _restaurants.OrderBy(r => r.Name); + } + } +} \ No newline at end of file diff --git a/OdeToFoodRider/OdeToFoodRider/Startup.cs b/OdeToFoodRider/OdeToFoodRider/Startup.cs index ab18d04..e3419db 100644 --- a/OdeToFoodRider/OdeToFoodRider/Startup.cs +++ b/OdeToFoodRider/OdeToFoodRider/Startup.cs @@ -20,6 +20,7 @@ public class Startup public void ConfigureServices(IServiceCollection services) { services.AddSingleton(); + services.AddScoped(); services.AddMvc(); } diff --git a/OdeToFoodRider/OdeToFoodRider/Views/Home/Index.cshtml b/OdeToFoodRider/OdeToFoodRider/Views/Home/Index.cshtml index d9e7b53..7cfe4e0 100644 --- a/OdeToFoodRider/OdeToFoodRider/Views/Home/Index.cshtml +++ b/OdeToFoodRider/OdeToFoodRider/Views/Home/Index.cshtml @@ -1,5 +1,5 @@ @using OdeToFoodRider.Models -@model Restaurant +@model IEnumerable @@ -8,7 +8,18 @@ My title -

@Model.Name

-
The ID value is @Model.Id
+@* VSRD: No table snippet in Rider. *@ + + + @* VSRD: No foreach live template here, just keyword completion like in Visual Studio *@ + @foreach (var restaurant in Model) + { + + + + + } +
@restaurant.Id@restaurant.Name
+ diff --git a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Controllers/HomeController.cs b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Controllers/HomeController.cs index f8e8b2a..3bb9d37 100644 --- a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Controllers/HomeController.cs +++ b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Controllers/HomeController.cs @@ -1,13 +1,26 @@ using Microsoft.AspNetCore.Mvc; using OdeToFoodVisualStudio.Models; +using OdeToFoodVisualStudio.Services; namespace OdeToFoodVisualStudio.Controllers { public class HomeController : Controller { + private IRestaurantData _restaurantData; + + // VSRD: Visual Studio doesn't have import items in completion, which means that here and in other cases when referencing an unimported type, you have to make sure to spell + // and capitalize it correctly, and then use a quick action to add an import. In Rider, import items are available in completion, which allows using camelHumps and abbreviations + // without being precise with naming, and additionally, accepting an import symbol suggestion adds the necessary using statement without the need to explicitly invoke a quick action. + public HomeController(IRestaurantData restaurantData) + { + // VSRD: VS provides a set of quick actions to generate _restaurantData (as a full or read-only field, full or read-only property, local variable), as well as explicit actions + // to change _restaurantData to IRestaurantData or restaurantData + _restaurantData = restaurantData; + } + public IActionResult Index() { - var model = new Restaurant { Id = 1, Name = "Scott's Pizza Place" }; + var model = _restaurantData.GetAll(); return View(model); diff --git a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/IRestaurantData.cs b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/IRestaurantData.cs new file mode 100644 index 0000000..eaf00f2 --- /dev/null +++ b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/IRestaurantData.cs @@ -0,0 +1,13 @@ +using OdeToFoodVisualStudio.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace OdeToFoodVisualStudio.Services +{ + public interface IRestaurantData + { + IEnumerable GetAll(); + } +} diff --git a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/InMemoryRestaurantData.cs b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/InMemoryRestaurantData.cs new file mode 100644 index 0000000..c44ed91 --- /dev/null +++ b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Services/InMemoryRestaurantData.cs @@ -0,0 +1,32 @@ +using OdeToFoodVisualStudio.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace OdeToFoodVisualStudio.Services +{ + public class InMemoryRestaurantData : IRestaurantData // VSRD: GetAll() implementation generated with Visual Studio's "Implement interface" quick action + { + // VSRD: Scott creates this constructor with the ctor code snippet - that's the only option with VS as there's no context action to initialize a field from constructor. + public InMemoryRestaurantData() + { + _restaurants = new List + { + new Restaurant {Id = 1, Name = "Scott's Pizza Place"}, + new Restaurant {Id = 2, Name = "Tersiguels"}, // VSRD: Visual Studio's Shift+Enter doens't add a comma after an object initializer + new Restaurant {Id = 3, Name = "King's Contrivance"} + + }; + // VSRD: in Scott's video, when creating the collection initializer (_restaurants = new List {}), Visual Studio adds the closing semicolon, + // but my VS fails to do so. + } + + List _restaurants; + + public IEnumerable GetAll() + { + return _restaurants.OrderBy(r => r.Name); + } + } +} diff --git a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Startup.cs b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Startup.cs index f35e607..e3e5120 100644 --- a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Startup.cs +++ b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Startup.cs @@ -18,7 +18,8 @@ public void ConfigureServices(IServiceCollection services) { // RDVS: Rider's completion works better with this generic method as it additionally adds the parentheses; additionally, VS overlaps the completion list inside the generic brackets // with with parameter info - services.AddSingleton(); + services.AddSingleton(); // singleton scope + services.AddScoped(); // per-HTTP-request lifeime services.AddMvc(); } diff --git a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Views/Home/Index.cshtml b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Views/Home/Index.cshtml index 66b718a..f7264d5 100644 --- a/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Views/Home/Index.cshtml +++ b/OdeToFoodVisualStudio/OdeToFoodVisualStudio/Views/Home/Index.cshtml @@ -1,13 +1,21 @@ @* VSRD: Visual Studio doesn't suggest importing the Restaurant model when typing @model Restaurant, so you have to type in the FQN. Let's see what Rider can do here :) *@ -@model OdeToFoodVisualStudio.Models.Restaurant +@model IEnumerable - @* VSRD: Visual Studio doesn't seem to provide Extend/Shrink selection in cshtml editor *@ -

@Model.Name

-
The ID value is @Model.Id
+ @* VSRD: Table generated in VS with a "table" code snippet *@ + + @* VSRD: No 'foreach' code snippet in VS, just keyword completion *@ + @foreach (var restaurant in Model) + { + + + + + } +
@restaurant.Id@restaurant.Name
\ No newline at end of file