Skip to content

Testing ASP.NET Core development workflows in JetBrains Rider and Microsoft Visual Studio, based on Scott Allen's Pluralsight course.

Notifications You must be signed in to change notification settings

gorohoroh/rider-visual-studio-asp.net-core-fundamentals

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

65 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

ASP.NET Core 2.0 with Rider 2018.2 and Visual Studio 2017

This document compares a developer's experience with an ASP.NET Core 2.0 application in two development environments: JetBrains Rider and Microsoft Visual Studio. For the purposes of providing an all-around, detailed comparison, the document walks through the various coding demos available in Scott Allen's ASP.NET Core Fundamentals course (as of November 9, 2017) on Pluralsight.

The steps outlined were taken in Visual Studio 2017 15.7.4 (RTM) and various Rider 2018.2 pre-release builds.

Creating a new ASP.NET Core Web Application with C# (Empty template)

Observations: Visual Studio πŸ’š

  1. Solution Explorer:
    1. Initially expanded to file level (good).
    2. Text editor area contains ASP.NET Core specific overview page with documentation links; Connected Services and Publish panes are available for navigation:
  2. Multimonitor support: all UI related to creating a project is shown on a single display.

Observations: Rider πŸ’›

  1. In the New Solution wizard, I can't select a directory using the updated Open File dialog; I have to enter the path to parent directory manually in the Solution directory text box, and no recent directories are available:
  2. Multimonitor support: Rider opened on display 1, New Solution wizard opened on display 2, then Select Solution Directory (Open File) opened on display 1 again.
  3. Initial IDE layout:
    1. Solution Explorer's solution node is collapsed (suboptimal);
    2. Scratches and Consoles node is visible (suboptimal, doesn't relate to the created project);
    3. Text editor area is empty, contains generic keymap hints:

Initial run of the application that we've just created

Observations: Visual Studio πŸ’š

All good. Built, ran using the default IIS Express launch profile. Output window shows output from ASP.NET Core Web Server, server says listening on port 17570, then requests going through a different port (54448) set in generated applicationhost.config, default browser (Chrome) automatically opens with the correct URL.

Links from the Output window can be Ctrl+clicked, which is a tiny bit worse than what Rider does.

Stopping is not clear: can't Ctrl+C in the Output window, and no Stop command is available in the Debug menu. The application can be either rerun from Visual Studio, or stopped using the separate IIS Express UI:

Observations: Rider πŸ’š

Accepted Default run configuration settings, built, ran.

Run tool window says listening on port 5000, further requests going through the same port.

Browser not automatically opened - however, clicking the link from the Run window works to open in default browser.

Stopping is clear: works with Ctrl+C in the Run tool window, as well as with the Stop Default command.

Notes, commits

I assume that the differences in start/stop experience are due to Visual Studio using IIS Express as a proxy to Kestrel and Rider using Kestrel directly.

Opening and editing a project file

Observations: Visual Studio πŸ’š

A project file can be opened in the text editor via right-click > Edit project file.

Quick Info tooltip is available on hover for valid .csproj elements:

Observations: Rider πŸ’š

A project file can be opened in the text editor via F4 or via right-click > Edit > Edit ....csproj.

No Quick Info is available on elements.

Creating a configuration file (appsettings.json)

Observations: Visual Studio πŸ’š

Right-click a project node > Add > New Item (or Ctrl+Shift+A) > ASP.NET Core > ASP.NET Core Configuration File (renamed to App Settings File in later VS versions). This provides a predefined name (appsettings.json), and the default file template contains a ConnectionStrings: DefaultConnection setting:

Observations: Rider πŸ’›

Right-click a project node > Add > JSON file. Just a generic JSON file template provided by WebStorm. No predefined name, empty content.

Modifying Startup.cs to use a value from appsettings.json

Observations: Visual Studio πŸ’š

Good editing experience in JSON and C#. Complete Statement doesn't work in JSON though, and importing a reference for IConfiguration is less obvious/comfortable than in Rider.

Observations: Rider πŸ’š

Good editing experience in JSON and C#. Import popup more useful than explicitly calling Ctrl+. in Visual Studio for importing a reference for IConfiguration.

Creating and injecting a custom Greeter service instead of hardcoded settings value

Observations: Visual Studio πŸ’š

All fine. Visual Studio handles Create from Usage and implementing interface members in a derived class, although not exactly as polished as Rider - good enough though:

  1. Visual Studio does allow implementing IGreeter from usage when the Greeter class has been declared; however, Rider does have the advantage of providing the Create derived type context action at IGreeter declaration.
  2. Visual Studio's Create from Usage isn't polished enough right now: given the undeclared IGreeter interface in method parameters and the below line that uses an undeclared method,
    1. The created symbol doesn't get focus: both when it's created in a separate file and when it's created in the same file;
    2. Roslyn doesn't infer that the generated method should return a string, not an object.

Observations: Rider πŸ’š

All fine. Regular C# coding that involves Create from Usage and implementing interface members in a derived class.

Notes, commits

Commit link

Configuring middleware: using IApplicationBuilder

Observations: Visual Studio πŸ’š

Good enough. Regular C# editing with certain issues both in Rider and Visual Studio. For example, VS completion breaks down after the await keyword - it just no longer suggests anything. Workaround: type a sync statement first, then add the await keyword. Rider handles this just fine. See commit for details and context.

Observations: Rider πŸ’š

Good enough. Regular C# editing with certain issues both in Rider and Visual Studio. For example, Rider's completion doesn't expect an identifier after the async keyword, so it starts to suggest weird classes, and this is where completion on space hurts: I wanted to type an unresolved symbol, context, but completion triggered on Space and inserted the unwanted ContextBoundObject class. A similarly bad completion experience on unresolved symbol just below: I wanted to use the undeclared logger to add it as parameter later, but got Logger<> completed instead. See commit for details and context.

Additionally, Rider displays an annoying Parameter Info tooltip in random spots inside the delegate:

Notes, commits

Commit link

Configuring middleware: showing exception details and configuring environment-specific middleware

Observations: Visual Studio πŸ’š

Good enough in terms of C# editing.

Launch settings are natively supported, as opposed to Rider.

appsettings.Development.json was automatically nested under appsettings.json and didn't require any manual configuration.

Observations: Rider πŸ’›

Good enough in terms of C# editing, although the Use string interpolation context action wasn't available when I needed it:

Rider doesn't pick environment or any other settings from launchSettings.json because it doesn't support launch settings: neither are they created with the ASP.NET Core template nor are they reflected in run configurations. Instead, environment variable settings in the default run configuration must be edited to switch to a different environment:

Creating appsettings.Development.json:

  1. Creating via copy-paste of appsettings.json works a little better than in Visual Studio because Rider suggests entering a name for the copy before actually creating it, and then suggests adding the new file to Git.
  2. However, Rider doesn't by default nest appsettings.Development.json under appsettings.json as Visual Studio does. I had to click File Nesting Settings in the toolbar and manually enter a nesting rule: parent: .json, child: .Development.json.

Notes, commits

Commit link

Neither in Visual Studio nor in Rider was I able to replicate Scott's exercise that involved displaying a Greeting value from appsettings.Development.json - probably a configuration mishap by me.

Configuring middleware: serving static files

Observations: Visual Studio πŸ’š

All good. Involves regular C# editing + creating an HTML file.

Observations: Rider πŸ’š

All good. Involves regular C# editing + creating an HTML file.

Live template for HTML file in Rider is slightly better as it places a hotspot at the value of the <title> tag, and then Rider suggests adding the new file to Git.

Notes, commits

Commit link

Along with creating an HTML file, Visual Studio removes a section that includes the wwwroot folder from the .csproj file. Rider doesn't do that. Unsure if this has any side effects so far.

Configuring middleware for ASP.NET MVC and adding a simple Home controller

Observations: Visual Studio πŸ’š

Viewing NuGet dependencies in Solution Explorer works fine.

Adding a directory in Visual Studio is harder: for some reason, Visual Studio's New folder is only available as a separate contextual command, and not as an item in Add New Item (Ctrl+Shift+A).

Observations: Rider πŸ’š

Viewing NuGet dependencies in Solution Explorer works fine. Manage NuGet Packages command is available in contextual menu for more nodes of the Dependencies tree than in Visual Studio, which is fine.

Adding a directory is easier in Rider as it can be done via Alt+Insert, along with adding new files.

Rider's lowerCamelCase and CamelCase completion matching is inferior to Visual Studio in simple cases like the below. Visual Studio suggests the expected UseStaticFiles() method matching usf; Rider suggests UseDefaultFiles() instead, both when matching with usf and USF (!!!!):

vs

Notes, commits

Commit link

Setting up conventional routing

Observations: Visual Studio πŸ’š

All fine with C# editing and adding a new controller.

Observations: Rider πŸ’š

All fine with C# editing and adding a new controller.

Notes, commits

Commit link

Setting up attribute routes

Observations: Visual Studio πŸ’š

C# editing around attributes works as expected.

Observations: Rider πŸ’›

Editing C# attributes works fine; however, import completion for the [Route] attribute is severely hanging:

Notes, commits

Commit link

Action results: deriving from the Controller base class, modifying an action to return IActionResult, creating a Restaurant model, instantiating and returning a model instance from the controller

Observations: Visual Studio πŸ’š

All good in terms of editing C# and creating a new directory and a new model (except that creating a new directory is a separate action - see one of the above Visual Studio notes).

Observations: Rider πŸ’š

All good in terms of editing C# in the controller and creating a new directory for models and a new model in it (tested using Move context action and refactoring).

Notes, commits

Commit link

Creating and rendering a view

Observations: Visual Studio πŸ’›

Visual Studio is lagging behind severely in this scenario:

  1. You can't create a view from usage, at all.
  2. This means if you're creating the default initial folder structure for models, you have to create a directory twice (separate action), and then use Add New Item to create a view.
  3. In the view, Scott right away removes the default content and uses the html template to roll out a barebones HTML structure. (This template isn't available in Rider but it's not needed there because Rider's default template for a Razor view is way better and already contains an HTML skeleton.)

When manually typing a model (@model Restaurant), Visual Studio doesn't suggest importing the model namespace - you need to manually type in an FQN.

Visual Studio doesn't provide Expand/Contract Selection commands in Razor views.

Visual Studio's completion only suggests the uppercase @Model property outside of the imports; however, it doesn't suggest anything when you type the lowercase @model, which means Rider's problem with suggested casing isn't as serious as it looks, because there's no typing habit for Rider completion to break when dealing with Visual Studio typing patterns.

Observations: Rider πŸ’š

Rider is superior in this scenario: creating a view from usage (return View(model);) in the controller:

  1. Creates the entire folder structure for views along with the actual view.
  2. The view is auto-typed with the model (if the model is provided) via a @model directive.
  3. @using directives are automatically inserted, and a hotspot is placed at the bare HTML's <title> tag value.

One small hiccup is that when importing the model, FQN is used both in the model and in the using statement whereas it's only required in the using statement.

If a Razor view is created using a file template, the resulting view is more complete as well.

When manually typing a model (@model Restaurant), Rider auto-imports the model namespace; Visual Studio doesn't do this.

Rider makes Extend/Shrink Selection available in Razor views whereas Visual Studio doesn't.

Other than that, when using the imported model in Razor markup, it's quite annoying that completion suggests @model when model is typed, even though the lower-case @model is only applicable as the import statement, and @Model should be provided instead.

Notes, commits

Commit link

Populating with data: creating a Services directory and moving IGreeter service there

Observations: Visual Studio πŸ’›

Moving IGreeter.cs to the new Services directory by drag-n-drop in Solution Explorer. Requires updating the namespace in IGreeter, then compiling and going through several CS0246 build errors to add a missing using directive in Startup.cs.

Subpar manual experience as Visual Studio doesn't have a Move to Folder refactoring (in fact, no Move refactorings at all, and no refactorings available on Solution Explorer nodes.)

Observations: Rider πŸ’š

Creating a new directory, again, is a bit easier. Rider modifies the .csproj file with a new folder include but Visual Studio doesn't do that: again, unclear differences in project model handling although it looks like Rider uses Visual Studio 2017's MSBuild distribution.

Moving IGreeter.cs to the new directory can be done with drag-n-drop, in which case Rider's VCS integration interprets the operation as a move (whereas the Visual Studio's drag-n-drop is seen as a file deletion + file addition). However, moving with drag-and-drop in Rider seems to introduce differences in line endings!

The better way to move IGreeter.cs to the new directory is certainly via Refactor This > Move to Folder on the file node in Solution Explorer. Invoking the refactoring with default settings (that include fixing namespaces) just works. Good job:

Notes, commits

Commit link

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

Observations: Visual Studio πŸ’›

Visual Studio does it all fine actually; yellow here just means that Rider is significantly better during this coding segment.

  1. Creating IRestaurantData via Ctrl+Shift+A: fine.
  2. Creating the derived InMemoryRestaurantData class: also has to be done with Ctrl+Shift+A because there's no action to create a derived type.
  3. Writing code in InMemoryRestaurantData: all fine, with a few notes:
    1. When modifying the class declaration to implement IRestaurant, Visual Studio provides Implement interface and Implement interface explicitly quick actions. Nice.
    2. Scott creates an InMemoryRestaurantData() constructor with the ctor code snippet - nice, but that's the only option with Visual Studio as there's no context action on a field to initialize the field from constructor.
  4. Modifying the Home controller: good. Notes:
    1. Visual Studio doesn't provide import items in completion, which means that when referencing a non-imported 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.
    2. Visual Studio 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:
  5. Modifying the Home view: good. Notes:
    1. There's a table code snippet to generate an HTML table in Razor markup, nice.
    2. However, there's no foreach code snippet, just keyword completion.

Observations: Rider πŸ’š

  1. Creating IRestaurantData via Alt+Ins: good, and again, Rider suggests to add the new file to Git right away.
  2. Declaring an interface member: Complete Statement at GetAll{caret} generates both the parentheses and the semicolon, Visual Studio doesn't do this.
  3. Creating InMemoryRestaurantData class: can be done with Alt+Ins but can also be done easier with a context action on IRestaurantData declaration to create a derived type:

    Then, there's a quick-fix to implement the interface, and a context action to move to a separate file.
  4. Writing code in InMemoryRestaurantData: good. Notes:
    1. 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 the Change Signature refactoring doesn't do that, too. No big deal to do this by hand though.
    2. Rider's code completion after the new keyword in collection initializer results in new Restaurant(), but the parentheses become redundant once braces are added for initializing properties. A typing assistant that removes redundant parentheses wouldn't hurt here.
  5. Modifying the Home controller: great! Notes:
    1. This time, after declaring a field and calling the Initialize field from constructor quick-fix, it does exactly what we want: declares a constructor with a IRestaurantData parameter. Nice!
    2. After modifying the parameter returned in View() to a collection of restaurants, Rider shows an error and suggests to modify the type of the view. Super nice!
  6. Modifying the Home view. Works, however:
    1. No live template for an HTML table in Razor views. As a side note, there is one in HTML files handled by WebStorm, but it only generates a <table> tag pair, with no rows or cells inside - Visual Studio does better here.
    2. No foreach live template in Razor, only keyword completion - same as in Visual Studio. Also, no way to surround markup with braces.

Notes, commits

Commit link

Creating and using a view model for the Index view

Observations: Visual Studio πŸ’›

Again, Visual Studio does a good job, it's just Rider that does it better.

  1. Creating a directory and a file for the first view model: all fine.
  2. Modifying the controller: fine. Initialize field from constructor would be handy but it's not there. As a side note, Visual Studio now provides a quick action to use object initializer - the action is available from the constructor call only though, not from variable usages:
  3. Modifying the view: decent. Had to change model type by hand, after which it took Visual Studio ~30 seconds to re-resolve the Model in foreach, figure out it's now a HomeIndexViewModel and finally start suggesting view model properties in code completion.

Observations: Rider πŸ’š

  1. Creating a directory and file for view model: good (both can be created from Alt+Ins and using a Git add suggestion.) Again, import items in completion rock!
  2. Modifying the controller: great. Initialize field from constructor rocks after declaring the _greeter field! Use object initializer is available both on constructor call and on further variable usages. The Change view model type quick-fix rocks again!
  3. Modifying the view: considerably better than Visual Studio because the model type has already been changed for us, and because Model is resolved quicker, with valid completion suggestions available instantly.

Notes, commits

Commit link

Creating a new Home controller action Details(int id), updating services with a new Get(int id) method to return details for a particular restaurant, creating a simple Details view, updating the Index view to use tag helpers and creating a required _ViewImports.cshtml along the way.

Observations: Visual Studio πŸ’›

Visual Studio does the job but in a lot less intelligent way than Rider.

  1. Creating a Details(int id) action in the Home controller: decent.
    1. Some code completion issues in Visual Studio when using a new method Get(id) before declaring it; creating the method in the interface from usage works (doesn't insert an implementation stub in the derived InMemoryRestaurantData though).
    2. Returning RedirectToAction("Index") works but Visual Studio doesn't provide code completion for actions in the string literal, and Scott prefers to use nameof(Index) instead; when returning a View(model).
    3. Visual Studio doesn't see that the view doesn't exist and doesn't suggest to create one.
  2. Updating services with a new Get(int id) method: fine. When going to the derived InMemoryRestaurantData, Visual Studio does provide a quick action to implement the new interface method.
  3. Creating the Details view: OK. No completion for controller and action names in tag helpers though.
  4. Creating _ViewImports.cshtml: OK, using a specialized item via Ctrl+Shift+A. However, Visual Studio provides no completion for the assembly name refrenced from _ViewImports.cshtml.
  5. Modifying the Index view to render links to restaurant details using 3 different kinds of syntax: <a href>, @Html.ActionLink and a tag helper. Visual Studio provides completion for tag helper attributes but, again, there's no code completion for controller and view names in string literals - only for C# symbols after @.

Observations: Rider πŸ’›

Mixed result: Rider shines with a few great features in this segment but there's a bunch of bugs as well.

  1. Creating a Details(int id) action in the Home controller: OK.
    1. Similar code completion issues in Rider. Creating a method from usage works and also doesn't insert an implementation stub in the derived class; however, provides a placeholder to change the default return type from object to something else (Restaurant) in our case.
    2. A null check on model is easier to introduce with the Check variable for null context action that is conveniently available at the end of the statement; a quick path to null check pattern settings is provided, too - nice!
    3. When returning RedirectToAction("Index"), Rider provides code completion for actions in the string literal that is passed over as parameter as well as navigation to action, nice!

      Using nameof(Index) is a bit problematic due to a ReSharper bug (RSRP-469876) but if it's just typed in without completion, Rider actually continues to provide navigation to the view!
    4. When returning a View(model), Rider detects that the referenced view is missing and suggests to create it:
  2. Updating services with a new Get(int id) method: fine. There actually is a (poorly discoverable) context action to implement the new interface method in derived classes:

    Good to know it's here but I'd expect a quick-fix instead. All in all, fine editing in both services.
  3. Creating the Details view: good, with a few quirks!
    1. Created with a quick-fix from controller (see above) - nice!
    2. However, model completion suggests an unqualified Restaurant type, which then triggers an import action, and all that ends up with FQNs in both @using and @model directives - which, in turn, requires removing FQN from the @model directive with a quick-fix. Also, the file template's active hotspot in the <title> tag prevents from calling Alt+Enter on the @model directive - you need to fill the hotspot first of all.
    3. ModelExpressionProvider annoys as the first completion suggestion for both @mod and @Mod - should be @Model instead!
    4. Trying to write a tag helper but there's no completion for asp-* attributes and their values. This is because there's no _ViewImports.cshtml, and Rider doesn't provide a quick-fix to create one!
    5. However, after creating _ViewImports.cshtml (see next step), Rider starts to provide completion for both tag helper attributes (asp-action and such) and their values, nice!
  4. Creating _ViewImports.cshtml: with hiccups as there are no cshtml items in Alt+Ins on the Views folder (only on nested folders). Workaround: use a generic File file template. After creating _ViewImports.cshtml, there are no completion suggestions for assembly name in Rider, just like in Visual Studio :( - completion for the @addTagHelper directive is available though.
  5. Modifying the Index view to render links to restaurant details using 3 different kinds of syntax: fine, with a few hiccups:
    1. When entering the regular anchor with relative paths, Rider complains it doesn't recognize the relative path, suggests to set path mapping, then nothing happens but the inspection is gone. Trying to edit path mappings fails silently:
    2. Action link syntax: again, action resolve in string parameter; however, completion can be improved:
    3. Tag helper syntax: good! Rider even suggests asp-route-id that is derived from the Details action signature - something that Visual Studio doesn't do:

Notes, commits

Commit link

Adding a form to create restaurants

Observations: Visual Studio πŸ’›

Visual Studio does the job but Rider provides a lot more automation in this scenario.

  1. Link from Index.cshtml to a new Create() action: Visual Studio doesn't detect that there's no action yet. I need to create it manually in the next step.
  2. Creating a new Create() action in the Home controller. When returning View(), Visual Studio doesn't see there's no view yet.
  3. Creating a new CuisineType enum in Models: adding a new class, then changing it to enum and populating. OK.
  4. Adding a CuisineType property to the Restaurant model with the prop snippet: OK.
  5. Creating a Create.cshtml view manually. Notes:
    1. There are no import suggestions for non-FQN types when declaring a model, have to type in the FQN by hand, although code completion does help with FQN.
    2. Snippets are available for form, select, and input, nice!
    3. Completion of model properties in tag helpers such as asp-for, asp-items - nice!
    4. When referencing the CuisineType enum, Visual Studio doesn't provide an import suggestion, have to go up and type a @using by hand.

Observations: Rider πŸ’š

Even though there are code analysis and code completion bugs when editing a view, the overall experience in this scenario is much richer than in Visual Studio.

  1. Link from Index.cshtml to a new action: great! Rider sees that there's no Create() action yet, and provides a quick-fix to create one:
  2. New Create() action in Home controller auto-created with the quick-fix. Now, adding a reference to a view that doesn't exist yet - Rider detects this, suggests to create one, and it's there now (and added to Git). Great!
  3. Creating a new CuisineType enum in Models: can use the enum file template right away.
  4. Adding a CuisineType property to the Restaurant model: OK.
  5. Writing code in the Create.cshtml view (that was auto-created for us at step 2 above):
    1. No issue with model import as we referenced the model when the view was created, via a hotspot.
    2. No snippets for form, select, input are available.
    3. Completion list for the asp-for attribute can be improved:

      However, completion for model fields in asp-for value is available!
    4. Completion for CuisineType is available:

      However! When using the @ prefix ahead of the expression in the asp-items value (which compiles fine), Rider shows a bogus Cannot choose method from method group error and fails to resolve the type parameter. When the @ prefix is not used, Rider doesn't complain, and the application still compiles and runs (RSRP-469518)
    5. Completion for input types is available:

Notes, commits

Commit links:

Accepting form input: adding a restaurant edit model, modifying services, the Details view, and creating a new Home controller action

Observations: Visual Studio πŸ’š

Visual Studio does the job with less automation but Rider's bugs set back its functional advantages. Tie in this scenario.

  1. Creating a Create() action overload in the Home controller to convert input data into a new restaurant item.
  2. Creating a RestaurantEditModel input model in ViewModels via Add New Item - although this in fact could be created from usage in the Home controller, in which case the file would have been created in the Controllers folder and then should have been moved to ViewModels (and we know Visual Studio can't modify namespaces on drag-and-drop).
  3. Modifying the new Create() action in the Home controller to receive a RestaurantEditModel, all good.
  4. Adding route constraints (attributes) to the two Create() actions.
  5. Processing input model in the input Create() action. Using an Add() method from IRestaurantData that is not declared yet, and generating it from usage.
  6. Implementing the Add() method in InMemoryRestaurantData: Go to Implementation from IRestaurantData interface declaration (because there's no Go to Implementation on specific members), and using the Implement interface quick action to create a stub. Writing implementation code.
  7. Modifying the Details.cshtml view to show more data on the restaurant entry that we've just created.

Observations: Rider πŸ’š

Rider's workflow is better automated but there are annoyances along the way. They were reported earlier, so let's say this is a tie with Visual Studio.

  1. Creating a Create() action overload in the Home controller: OK. Creating RestaurantEditModel from usage. Created in the Home controller, then moved to a separate file with a context action (still under Controllers though), then Refactor This > Move to Folder to move the new file to ViewModels. Quite a complicated chain of actions but works, and Move to Folder does auto-adjust the namespace by default.
  2. Creating properties in RestaurantEditModel - good.
  3. Using Implement in derived classes CA in IRestaurantData to create an implementation stub in InMemoryRestaurantData and navigate there - great! Writing implementation logic - good.
  4. Adding route constraint attributes to the two Create() actions: hanging completion strikes again.
  5. Can navigate from the Home controller to Details.cshtml to modify the view. Modifying the view: OK, although, again, completion for @Model is annoying.

Notes, commits

Commit link

Adding a redirect to action to prevent duplicate POST requests

Observations: Visual Studio πŸ’š

Just a one-line change to the return of the POST-specific Create() action: OK. Used nameof for better completion because Visual Studio doesn't suggest view names in string literals.

Observations: Rider πŸ’›

Just a one-line change to the return of the POST-specific Create() action: OK. Used string literal for view name instead of the nameof approach in Visual Studio because of the nameof completion bug referenced somewhere above.

Notes, commits

Commit link

Adding model validation with data annotations in models, checking for valid model state in controller, and adding validation tag helpers in view

Observations: Visual Studio πŸ’š

Visual Studio is less feature-rich but more stable. Tie again.

  1. Updating Create.cshtml to add labels to form items. Wrapping tags with a div: Shift+Alt+W in Visual Studio. However the action is not reformatting the resulting markup, and as Extend Selection doesn't work in Razor, I have to select manually, then invoke Ctrl+K,F to reformat the selection.
  2. Updating the Restaurant model and the RestaurantEditModel view model with data annotations, using a quick action to import System.ComponentModel.DataAnnotations.
  3. Modifying the POST-specific Create() action to check if the model being passed is valid. Scott wraps a code selection with an if/else manually, although there are code snippets in Visual Studio.
  4. Updating Create.cshtml with placeholders for possible error messages using validation tag helpers.
  5. Adding the ValidateAntiForgeryToken attribute to the POST-specific Create() action.

Observations: Rider πŸ’š

Rider is better in terms of features, but the attribute completion tag is starting to annoy the hell out of me, thus a tie. Fix this, and Rider's going to be seriously better in this segment.

  1. Updating Create.cshtml to add labels to form items and placeholders for validation messages. Good. Completion for tag helpers and values works well; Surround with template lets me group label, input and span in a div. No auto-formatting on wrap but since Rider's Extend Selection works in Razor views, I can use that and then invoke Reformat Code on the selection.
  2. Updating the Restaurant model and the RestaurantEditModel view model with data annotations. Hanging attribute completion strikes again in both classes! (RIDER-16880), apart from this all fine. Context actions to move attributes between sections are nice!
  3. Modifying the POST-specific Create() action to check if the model being passed is valid. All good. Extend Selection to the entire method body, then wrapping with an if statement using Surround With. After that, either use an else template to return a view if model state is invalid (in which case the else block will be highlighted as redundant), or use a quick-fix on the Return statement is missing inspection to add a return:
  4. Adding the ValidateAntiForgeryToken attribute to the POST-specific Create() action: all fine.

Notes, commits

Commit link

Setting up a SQL Server LocalDB connection

Observations: Visual Studio πŸ’š

  1. The SQL Server Object Explorer view in Visual Studio shows available LocalDB instances:
  2. Although this is quite clumsy, you can get a connection string by opening properties of an instance:

Observations: Rider ❀️

  1. Go to Database > Add Data source > SQL Server.
  2. Try to set up a connection to SQL Server Local DB, give up, drop using Rider (DBE-6705).

Installing and configuring EF Core

Observations: Visual Studio πŸ’š

(EF Core is already installed as part of Microsoft.AspNetCore.All.)

  1. Searching for installed packages in Solution Explorer > project > Dependencies: OK
  2. Installing new packages via Dependencies > Manage NuGet Packages: OK.
  3. Editing .csproj to install Microsoft.EntityFrameworkCore.Tools.DotNet as a DotNetCliToolReference: OK, although tag name completion is very basic (no camelHumps support).
  4. Executing dotnet ef commands: via system shell or via bundled Package Manager Console.

Observations: Rider πŸ’š

(EF Core is already installed as part of Microsoft.AspNetCore.All.)

  1. Searching for installed packages in Solution Explorer > project > Dependencies: OK
  2. Installing new packages via Dependencies > Manage NuGet Packages: OK.
  3. Editing .csproj to install Microsoft.EntityFrameworkCore.Tools.DotNet as a DotNetCliToolReference: OK. Tag name completion is better (has camelHumps support). Highlighting for empty body of an XML tag is annoying (funnily, it goes away on introducing a line break):
  4. Executing dotnet ef commands: via system shell or via bundled Terminal window.

Notes, commits

Commit link

Creating an EF Core DbContext and a service implementation that works with the context

Observations: Visual Studio πŸ’š

Visual Studio does the job despite different commands to create items, no import completion.

  1. Creating a new Data directory and an OdeToFoodDbContext class in it. Again, two different commands to create a directory and a class. Again, since there are no import items in completion, you have to be careful to type in DbContext exactly and properly cased before Visual Studio suggests to add an import statement with a quick action.
  2. Creating a new SqlRestaurantData service to use instead of InMemoryRestaurantData. New class is created via Ctrl+Shift+A as there's no action to create a new derived class form an existing interface.
  3. Implementing SqlRestaurantData. The Implement Members action generates stubs, then it's regular code editing inside the stubs + creating a constructor with ctor, and a field to store the context with another quick action. All good.

Observations: Rider πŸ’›

Rider provides more automation and more convenience with its import items in completion; however, the Space completion behavior kind of counters the benefits.

  1. Creating a new Data directory and an OdeToFoodDbContext class in it. Both with Alt+Insert, Git addition suggested. Good. DbContext is available as an import item in completion, imported seamlessly. ctor, prop live templates work well.
  2. Creating a new SqlRestaurantData service to use instead of InMemoryRestaurantData. Better because you can navigate to IRestaurantData and invoke a context action Create derived type, then implement missing members, then use another context action to move to a separate file, and Rider suggests adding it to Git. Nice.
  3. Implementing SqlRestaurantData. When adding a constructor and adding a parameter to it, you can Alt+Enter on the parameter to generate a read-only field, which is fine; but another approach would be to start typing an undeclared field to create from usage later, and this is where Rider's stupid space completion ruins the act: pressing Space at this point will complete the irrelevant library type instead of allowing me to type in a yet-to-be-declared field:

    There's also a problem with Complete Statement with lambdas that I ran into (RSRP-470502) but it's unlikely to be a big deal for anyone unless they're using Complete Statement all the time.
    Otherwise C# editing is just fine.

Notes, commits

Commit link

Configuring EF Core services

Observations: Visual Studio πŸ’š

  1. Modifying appsettings.json to have a valid connection string (Visual Studio-specific DB): OK.
  2. Modifying Startup.cs to update available services and get access to connection string in appsettings.json. Fine. (Importing the unimported is a bit annoying, though, again.)

Observations: Rider πŸ’š

  1. Modifying appsettings.json to have a valid connection string (Rider-specific DB): OK.
  2. Modifying Startup.cs to update available services and get access to connection string: very fine. Import completion items help; creating a constructor with Alt+Ins, adding a parameter + a quick-fix to create a field works, unless I want to start with using an undeclared field (then I'd be hit by the Space completion problem described above.)

Notes, commits

Commit links:

Executing EF Core migrations

Observations: Visual Studio πŸ’š

  1. Executing dotnet ef migrations add InitialCreate via Windows Command Prompt: OK.
  2. Executing dotnet ef database update via Windows Command Prompt: OK.
  3. Checking that the database has been created via SQL Server Object Explorer in Visual Studio: OK.

Observations: Rider ❀️

  1. Executing dotnet ef migrations add InitialCreate via the Terminal window: OK.
  2. Executing dotnet ef database update via the Terminal window: OK.
  3. Checking that the database has been created via the Database window. Spent an hour trying to figure out why I don't see the right databases in the instance I'm connected to, then accidentally clicked the DB filter (:facepalm:):

Notes, commits

Commit link

Adding entries to the Restaurants table from the application and from IDE DB UI

Observations: Visual Studio πŸ’š

  1. SQL Server Object Explorer > DB > table > right-click > View Data - edit data in the editor, launch the application, see the data. Changes are committed to the DB on-the-fly. Intuitive Excel-like editor UI:
  2. Adding a new restaurant from application UI > refreshing DB editor in Visual Studio > new data is shown.

Observations: Rider πŸ’›

  1. Database view > find DB > table > press F4 to edit. Works fine if LocalDB is active; cryptic error messages otherwise (had to refresh from Visual Studio to make the errors go away):

    Editor is OK although Alt+Ins to add a row is less intuitive than in Visual Studio. To send added/modified data to database, got to click Submit.
  2. Adding a new restaurant from application UI > refreshing DB editor in Rider > new data is shown. Fine.

Creating a layout view and using it from the Index view

Observations: Visual Studio πŸ’š

Visual Studio does the job without notable issues.

  1. Creating a Shared folder and a layout view (Add New Item -> Razor layout, named _Layout.cshtml by default) inside. Two different commands but OK, at least the layout item template is there.
  2. Removing redundant markup from Index.cshtml. Then adding a title via ViewBag, as well as a path to layout (no path completion).
  3. Adding a @RenderSection block to _Layout.cshtml: OK.
  4. Adding a footer section to the Index view: OK.

Observations: Rider πŸ’›

Rider does the job but there are issues in file templates and completion.

  1. Creating a Shared folder and a layout view inside. Both folder and file are created via Alt+Ins, which is fine. However, there's no file template for a Razor layout! Workaround: create a regular view, call it _Layout.cshtml, remove the @model directive, add @ViewBag.Title and @RenderBody.
  2. Removing redundant markup from Index.cshtml. Then adding a title via ViewBag, as well as a path to layout. For layout path, there's reference completion that suggests available views, and this looks fine; HOWEVER, if I go Scott's way and start entering a file path from application root, the reference completion will hinder and eat the entered path as soon as completion is committed:
  3. Adding a @RenderSection block to _Layout.cshtml: OK.
  4. Adding a footer section to the Index view: OK.

Time and again, Rider seems to reformat .csproj files automatically on adding new files. Looks like RIDER-6450.

Notes, commits

Commit link

Creating _ViewStart.cshtml and editing titles in other views

Observations: Visual Studio πŸ’š

All goes as expected in Visual Studio

  1. Creating _ViewStart.cshtml in the Views folder: there's a special Razor View Start file template with the correct name and default content. All fine.
  2. Editing Create, Details views to define titles; editing the Index view to remove a layout reference because it's now in _ViewStart.cshtml: OK.

Observations: Rider πŸ’›

OK in Rider but a view start file template is missing.

  1. Creating _ViewStart.cshtml in the Views folder: there's no Razor view start file template available in the folder, nor are there any Razor templates. Workaround: use the generic file template.
  2. Editing Create, Details views to define titles and remove redundant HTML markup (Rider's file templates for views contain more of it than Visual Studio's templates); editing the Index view to remove a layout reference because it's now in _ViewStart.cshtml: OK.

Notes, commits

Commit link

Putting common using statements into _ViewImports.cshtml

Observations: Visual Studio πŸ’›

Visual Studio does the job but requires too much manual work.

  1. Editing _ViewImports.cshtml: OK, although FQN completion is clumsy.
  2. Going through views to remove redundant using directives by hand: no quick actions to do this in Razor files.

Observations: Rider πŸ’š

Rider does a far better job, thanks to completion and batch QFs.

  1. Editing _ViewImports.cshtml: good, completion works well.
  2. Going to the first view, and batch-executing two quick-fixes: Remove unused directives and Remove redundant qualifier. Nice!

Notes, commits

Commit link

Using Razor Pages

Observations: Visual Studio πŸ’›

Visual Studio does the job - nothing special though. A few code completion/code analysis issues along the way.

  1. Creating a Pages folder, adding a page via New Item > Razor Pages > Razor Page (additional templates include Razor Page using EF and Razor Page using EF (CRUD)) called Greeting.cshtml. All fine.
  2. Editing Greeting.cshtml: code completion for C# references is there.
  3. Copy/pasting _ViewImports and _ViewStart to the Pages folder, editing _ViewImports to use more namespaces.
  4. Editing Greeting.cshtml by adding an @inject directive (and Scott is having all kinds of issues with VS showing red code because of files not saved).
  5. Editing ViewStart to use a _Layout.cshtml in the Pages folder (which is not there); copy-pasting existing _Layout.cshtml to the Pages folder.
  6. Editing Greeting.cshtml to use a @model instead of @inject. This generates a code-behind file (Greeting.cshtml.cs, or was it there since adding the Razor page?) and also shows a nested and seemingly redundant_Pages_Greeting node:
  7. Editing code-behind: injecting service, getting message of the day within OnGet().
  8. Editing Greeting.cshtml to render a property on the code-behind, and adding a required parameter via the @page directive; editing code-behind to make use of the parameter (adding string interpolation)

Visual Studio has at some point modified the .sln file to change project GUID. Made a similar change in Rider manually.

Observations: Rider ❀️

It all goes wrong as soon as Rider fails to properly create an item for a Razor page; if this is resolved, then the overall experience should be solid.

  1. Creating a Pages folder: fine. Creating a Razor Page: no file template for Razor Pages; workaround: create a regular MVC view.
  2. Editing Greeting.cshtml: OK, though no completion after the @page directive.
  3. Copy/pasting _ViewImports and _ViewStart to the Pages folder, editing _ViewImports to use more namespaces: OdeToFoodRider.Pages (the Razor page code-behind) is unresolved:
  4. Editing Greeting.cshtml by adding an @inject directive: good! Rider even suggests a name for the injected property.
  5. Editing ViewStart to use a _Layout.cshtml in the Pages folder (which is not there). Rider highlights the reference _Layout.cshtml with red but doesn't suggest to create a page. Copy-pasting by hand doesn't remove red highlighting: Rider doesn't seem to understand the file system-based way to reference a layout in this case.
  6. Editing Greeting.cshtml to use a @model instead of @inject. Model is unresolved (because code-behind wasn't generated); creating from usage creates a regular class in the Pages directory, instead of a nested Greeting.cshtml.cs. Have to rename, after which it's properly nested. Changing namespace in the code-behind to .Pages fixes resolve from ViewImports.
  7. Editing code-behind: injecting service, creating OnGet() and displaying message of the day: all fine but OnGet() is highlighted as never used.
  8. Editing Greeting.cshtml to render a property on the code-behind, and adding a required parameter via the @page directive; editing code-behind to make use of the parameter: OK.

Notes, commits

Commit link

Adding the Edit form using Razor Pages

Observations: Visual Studio πŸ’š

VS gets the job done, with usual small annoyances (no import completion, shaky code analysis in Razor page view etc.)

  1. Adding a new Pages/Restaurants directory and Edit.cshtml Razor page (file template with code-behind).
  2. Adding a link to the new page from the Index view.
  3. Copying over a form from the Create view to Edit.cshtml and adapting (such as adding a hidden input for restaurant ID).
  4. Adding the Update() method to IRestaurantData and derived types (just a stub in InMemoryRestaurantData).
  5. Editing Edit page code-behind with a constructor accepting an IRestaurantData and saving to a field, a bind property to hold and update restaurant information, implementing OnGet(int id) and adding OnPost() with model validation.

Observations: Rider πŸ’›

Rider provides a few nice features but again, there's no way to easily create a Razor page with code-behind + there's an array of minor annoying bugs. Yellow because the Red flag for the lack of the file template had already been given.

  1. Adding a new Pages/Restaurants directory and Edit.cshtml Razor page. Again, no Razor Page file template, had to apply a workaround by creating a Razor view + codebehind file (which was created with a weird ASP namespace instead of the proper OdeToFoodVisualStudio.Pages.Restaurants). After misplacing the new Razor page file, moved it to the right directory with Move to Folder, which introduced a line ending-only change in .csproj. Editing the Razor page triggered a flow of exceptions in Rangeable container, Rider protocol, typing assists etc. Unfortunately this is not easily reproducible, so just updated Rider to the latest nightly instead.
  2. Adding a link to the new page from the Index view: OK.
  3. Copying over a form from the Create view to Edit.cshtml and adapting. Again, completion at asp-for could be better. Otherwise fine, especially nice to be able to use the Change All quick-fix to correct copy-pasted model references:
  4. Adding the Update() method to IRestaurantData and derived types. The Implement in derived types context action and its type selector: nice!

    Shortcut completion for enum members is nice, too:

    Overall a very solid editing experience.
  5. Editing the Edit page's code-behind. Attribute completion strikes again! Introduce readonly field quick-fix from constructor is useful here, again (although every time I call it I wonder if the generated field should in fact be read-only). OnGet(), OnPost() are highlighted as unused. Action and controller arguments of RedirectToAction() are highlighted as regular string literals, as opposed to their special treatment in MVC controllers:

    The if live template continues to be deployed into a weird if(b). Otherwise fine.

Notes, commits

Commit link

Refactoring the Index view to use a new _Summary partial view

Observations: Visual Studio πŸ’š

All fine in Visual Studio.

  1. Editing the Index view to use a partial view for each restaurant summary instead of a table.
  2. Creating a _Summary.cshtml partial view under Views/Home with Add New Item. Adding markup to display a restaurant summary. Copying links to Details and Edit views from Index.cshtml and adapting them.

Observations: Rider πŸ’š

Rider works well enough. Creating views from usage doesn't work here for whatever reason but Visual Studio doesn't have that, too. On par with Visual Studio although there are bugs to be reported.

  1. Editing the Index view to use a partial view for each restaurant summary. View completion in string literals is nice! We need to reference a view that's not created yet though. Removing the table is easier with Extend Selection (which in Visual Studio is only available in C#). Surrounding the Create action link with a <div> via Surround With works but does so in a weird way, using the <a/> tag by default, and putting a hotspot on the closing tag instead of the opening tag.
  2. Creating a _Summary.cshtml partial view, and it looks like we can do that from usage!

    HOWEVER, it looks like no, we can't - for no particular reason:

    OK, creating from live template then.
  3. Editing _Summary.cshtml. No sync-editing of HTML tags, and on a mismatch between the opening and the closing tag, the Insert closing tag quick-fix adds a new closing tag instead of replacing the mismatching one. Otherwise fine; using Change All again to replace a variable with Model.

Notes, commits

Commit link

Moving the footer section to a new view component

Observations: Visual Studio πŸ’š

Visual Studio does the job at its usual standard although creating the directory hierarchy for view component view is particularly tricky.

  1. Creating a ViewComponents folder and a GreeterViewComponent.cs class inside. Adding a constructor and the Invoke() method referencing a view that doesn't exist yet.
  2. Removing the footer section from Index.cshtml as it's going to be a view component.
  3. Under Views/Shared, creating directory hierarchy Components/Greeter, and a new Razor view inside to be used by the view component: Default.cshtml. Creating these 3 items is a bit painful in VS. Very few edits to the view.
  4. Editing _Layout.cshtml to include 2 alternative ways of invoking the view component. One of them, the tag helper way, requires adding another directive to _ViewImports.cshtml - by hand.

Observations: Rider πŸ’›

Rider makes a statement to be better with the quick-fix to create view component views from usage - however, the quick-fix is unfortunately broken.

  1. Creating a ViewComponents folder and a GreeterViewComponent.cs class inside; adding logic to the class. All good, Create readonly field from constructor parameter helps again.
  2. Trying to create the Default view for the view component with a quick-fix:

    It doesn't work unfortunately, throwing DEXP-361709 along the way. OK, creating manually, which is less cumbersome to do than in Visual Studio anyway. Adding simple view content, all fine.
  3. Editing _Layout.cshtml to invoke the view component in two ways. Completion for view component class in string literals is a nice surprise:

    Neither Rider nor Visual Studio provide completion for the tag helper syntax. Adding a directive to _ViewImports.cshtml - OK although there's no completion for namespaces, much like in Visual Studio.

Notes, commits

Commit link

Switching over to using SSL

Observations: Visual Studio πŸ’š

Visual Studio makes the process easy. Automating the generation of a self-signed certificate is especially appreciated.

  1. Switching to use SSL: Project properties > Debug > Enable SSL. A new URL is generated, copying it to the adjacent App URL setting. The actual settings are stored in launchSettings.json > iisExpress. When first trying to start an application that is configured to use SSL, Visual Studio suggests that a self-signed certificate is generated by IIS Express for development purposes, and then suggests to trust the certificate.
  2. Adding the Rewriter() middleware to Startup.cs with an option to permanently redirect all HTTP to HTTPS requests.

Observations: Rider ❀️

Poor experience. Running ASP.NET Core on IIS Express is not supported (RIDER-11638), thus you need to search for and go through a way to configure Kestrel to use SSL, which is not trivial. You also have to take care of generating a certificate with a PowerShell script on Windows or using a separate procedure on Mac/Unix.

  1. Switching to use SSL. Since Rider uses Kestrel directly, and even if it did use IIS Express as a proxy, it doesn't understand launchsettings.json, I need to set up SSL in Kestrel instead. Rider doesn't help at all with generating a certificate. Had to generate a certificate and configure Kestrel to use HTTPS and the certificate based on this guide. (Microsoft's own documentation is way less helpful.) Quite a painful and time-consuming process.
  2. Adding Rewriter() middleware - OK.

Notes, commits

Commits:

Registering with an OpenID provider, adding OpenID configuration, configuring services and middleware, marking controllers, actions and page code-behind to use authorization

Observations: Visual Studio πŸ’š

Visual Studio does the job, with some annoyances like no import items in completion (which bites in OAuth configuration).

  1. Scott creates an app registration using his Azure AD B2C user account:

    I registered two OAuth apps (one for Rider and one for Visual Studio) with my GitHub account instead.
  2. Adding OAuth-related settings, modifying Startup.cs and Program.cs - a mix of Scott's actions and this tutorial that is .NET Core/GitHub-specific. All regular C# and a bit of JSON editing. Fine but again, no import items in completion is a pain in Visual Studio. Also, copy-pasting isn't enjoyable as each unimported symbol must be imported with a separate quick action. Rider/ReSharper are way better in this regard.
  3. Marking the Home controller and its actions, as well as the Edit page code-behind with [Authorize] and [AllowAnonymous] attributes.

Observations: Rider πŸ’š

Rider does the job albeit with its own share of annoyances (import completion in attributes!) Copy-pasting code in Rider is enjoyable though, thanks to import suggestion that adds all imports at once.

  1. Using two GitHub app registrations (separate for Rider and Visual Studio).
  2. Adding OAuth-related JSON settings file, modifying Startup.cs and Program.cs to implement GitHub-based OAuth, using the same mix of Scott's video and a .NET Core/GitHub-focused tutorial as in the Visual Studio part. Copy-pasting parts from Visual Studio, and the import pop-up rocks in that it imports everything at once!
  3. Marking the Home controller and its actions, as well as the Edit page code-behind with [Authorize] and [AllowAnonymous] attributes. Import completion in attributes strikes again!

Notes, commits

Commit link

Displaying information about user identity

Observations: Visual Studio πŸ’š

Adding markup and code to _Layout.cshtml that goes through user identity information and displays claim values. Regular Razor editing. All fine.

Observations: Rider πŸ’š

Adding markup and code to _Layout.cshtml that goes through user identity information and displays claim values. Regular Razor editing. All good.

Notes, commits

Commit link

Adding package.json and installing Bootstrap

Observations: Visual Studio πŸ’š

Polished experience in Visual Studio. npm dependency indication in Solution Explorer is a nice bonus. The default content of package.json is a bit different from Rider.

  1. Adding package.json to the project via Add new item -> npm configuration file template. This introduces a new npm node in project dependencies. (node_folders isn't shown by default though, unless Show all files is on.
  2. Adding a bootstrap dependency in package.json > saving > Visual Studio auto-installs the package. Completion in package.json is very solid: both for property names (incl. packages available in npm) and values (versions of the packages).

Observations: Rider πŸ’š

Very solid experience in Rider, too. No dependency indication in Solution Explorer but overall smoother in terms of adding and editing package.json. Explicitly suggesting to start installing dependencies is probably a safer approach, too.

  1. Adding package.json to the project via WebStorm's file template, which suggests a name based on project name - nice touch!
  2. Adding a bootstrap dependency. Completion in package.json is on par with Visual Studio, it looks like it even works faster. Rider doesn't auto-install but instead, suggests to install dependencies, and does that if I allow it to:

    The only downside is that there's no npm node in the project's Dependencies node in Solution Explorer, so you can only see there are installed dependencies if you choose to Show all files.

Notes, commits

Commit link

Writing an application builder extension method to enable serving files from node_modules (as an alternative to using something like gulp or Grunt)

Observations: Visual Studio πŸ’›

Visual Studio: decent experience with ups and downs: drag-and-drop CSS to put a link reference to it is nice, but having to use an external namespace to enable code completion is not.

  1. Adding an undeclared application builder extension method to Startup.cs that would enable serving static files. Visual Studio can't create extension methods from usage.
  2. Adding a Middleware folder and a new class in it to implement the extension method. Putting the class in the Microsoft.AspNetCore.Builder namespace to enable Visual Studio's code completion to see it :(
  3. Editing _Layout.cshtml to refer to bootstrap.css in node_modules. Visual Studio can generate a link tag with the right path when you drag-and-drop bootstrap.css from Solution Explorer, quite a nice touch.

Observations: Rider πŸ’›

Rider: also up and down. Not being able to create extension methods from usage is sad. Completion issues in paths are annoying, too. C# editing is good though, so let's make it even.

  1. Adding an undeclared application builder extension method to Startup.cs that would enable serving static files. Shocking fact: Rider can't create an extension method from usage, either:
  2. Adding a Middleware folder and a new class in it to implement the extension method. Smooth C# editing. Rider shows the extension method on call site without having to put it into an external namespace.
  3. Editing _Layout.cshtml to refer to bootstrap.css in node_modules. Writing a link by hand. Rider doesn't recognize ~-prefixed paths and provides no sensible completion when you write the path. (A similar path problem occurred earlier in the course, see above.)

Notes, commits

Commit link

Styling views with Bootstrap

Observations: Visual Studio πŸ’›

Adding Bootstrap classes to various elements across Razor views and layouts. Visual Studio's code completion isn't helpful at all (suggests certain Bootstrap classes but they aren't what I need every single time - this is probably hippie completion for class names that were already used).

Observations: Rider πŸ’›

Adding Bootstrap classes to various elements across Razor views and layouts. Completion is unhelpful, too, and as in Visual Studio, it's probably hippie completion. I assume that these problems are related to the way bootstrap.css is referenced in _Layout.cshtml.

Notes, commits

Commit link

Adding client-side validation

Observations: Visual Studio πŸ’š

All fine in Visual Studio. Well, maybe generating script/link references with drag-and-drop is not as nice as I thought, as it requires quite a bit of precise mouse manipulation and adding new lines in the editor beforehand.

  1. Adding a few more dependencies into package.json, they're then auto-installed.
  2. Drag-and-dropping each of the installed dependencies into _Layout.cshtml to generate script references to them.

Observations: Rider πŸ’›

Rider is doing great in terms of package.json editing but disappoints when editing script references (path completion).

  1. Adding a few more dependencies into package.json. The Update Dependencies popup is late to show up this time but there's also a quick-fix to run npm install that is available earlier, nice!
  2. Typing script references by hand. Tried to go up to project folder in path completion but weirdly enough, it doesn't see the node_modules directory at all:

    It's a bit better when completing from root this time (node_modules can be seen on ~/{caret}) but after the next slash, path completion starts to look into project root instead of showing what's inside node_modules:

Notes, commits

Commit link

Using CDNs in production environment

Observations: Visual Studio πŸ’š

Wrapping script and link references in _Layout.cshtml with the <environment/> tag and using various ASP.NET tag helpers to test if scripts and stylesheets have in fact been delivered from a CDN.

Visual Studio does a very good job providing code completion for tag helper attributes in the <link/> tag:

Wrapping markup with tags is a bit cumbersome though.

Observations: Rider πŸ’›

Wrapping with tags is more fluid with surround templates but there's a bug whereby after applying the surround template, a hotspot is put in the closing tag (this already occurred in one of the prior segments).

Unfortunately, Rider provides zero completion both for the <environment/> tag, its attributes and values, as well as for the tag helpers that are available inside the <link/> and <script/> tags (asp-fallback-test-class etc.).

This is missing functionality but let's go with yellow instead of red as this isn't a very mainstream scenario.

Notes, commits

Commit link

About

Testing ASP.NET Core development workflows in JetBrains Rider and Microsoft Visual Studio, based on Scott Allen's Pluralsight course.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published