.NET Core Application Development in Visual Studio Code (VS Code)

Posted by: Damir Arh , on 7/28/2018, in Category Visual Studio
Views: 60572
Abstract: This tutorial explores how to develop .NET Core applications in Visual Studio Code (VS Code). We will explore some extensions that enhance Visual Studio Code and improves your .NET Core development experience.

The official C# extension allowed developers to use Visual Studio Code from the beginning as a light-weight editor for .NET Core projects. With many other extensions created by members of the community, .NET Core development has become easier and enjoyable.

In this article, I will inspect some of these extensions and help you configure Visual Studio Code to make these extensions work together. If you’re not familiar with Visual Studio Code, you can learn more about it from my previous article Visual Studio Condensed.

This tutorial is from the DotNetCurry(DNC) Magazine with in-depth tutorials and best practices in .NET and JavaScript. This magazine is aimed at Developers, Architects and Technical Managers and covers C#, Patterns, .NET Core, MVC, Azure, DevOps, ALM, TypeScript, Angular, React, and more. Subscribe to this magazine for FREE and receive all previous, current and upcoming editions, right in your Inbox. No Spam Policy.

Visual Studio Code for .NET Core

Manipulating Projects and Code Files

If you’re used to Visual Studio (VS 2015, 2017 and so on), the Solution Explorer window will probably be the first thing you’ll miss when you try opening your .NET Core solutions in Visual Studio Code a.k.a. VS Code.

The Solution Explorer in Visual Studio renders the projects in your solution as a tree view. This view contains the individual source code files. It also contains virtual nodes with additional important information about your projects, such as references to NuGet packages and other projects stored in the project file.

solution-explorer-in-visual-studio-2017

Figure 1: Solution Explorer in Visual Studio 2017

Visual Studio Code revolves around folders, not solution files. Its main navigation tool is the Explorer view which lists all the files and subfolders of the currently opened root folder. In a typical .NET Core solution, all its projects are inside the same solution folder. This simple list of files does not provide the same level of information as the Solution Explorer does in Visual Studio.

dotnet-core-solution-folder-vscode

Figure 2: .NET Core solution folder in Visual Studio Code Explorer view

Fortunately, there’s an extension available which can help with that.

If you install the vscode-solution-explorer extension in your copy of Visual Studio Code, it will add a Solution Explorer view to it.

It’s not a fully featured equivalent to the Visual Studio Solution Explorer, but it does follow the same concept of reading the information from the solution and project files, and rendering it in a tree view with the solution and its projects as the main nodes.

solution-explorer-view-in-visual-studio-code

Figure 3: Solution Explorer view in Visual Studio Code

The extension not only displays the solution in a different manner but also adds context menu commands for creating solutions, projects and code files. You can use these commands instead of running dotnet commands directly from a terminal:

- To create a new solution when you have an empty folder open in Visual Studio Code, invoke the Create new empty solution command by clicking on the No solution found text in the Solution Explorer pane or by invoking it from the Command palette. After entering the name, the solution will be created by executing the following dotnet command:

dotnet new sln -n VsCodeDotNetCore -o C:\Users\Damir\Temp\VsCodeDotNetCore

Once the solution is created, the extension will encourage you to create a template folder.

If you approve the request, it will create the .vscode/solution-explorer folder for you. Inside it, the extension will put a collection of special template files it is distributed with.

When you’ll create new code files through the extension (as explained later in the article), one of these templates will be used as the starting content for the new file. Along with the other files that Visual Studio Code itself puts in the .vscode folder (e.g. launch.json with launch configurations and settings.json with workspace settings), make sure to include the created template folder in the source control.

notification-creating-templates-folder

Figure 4: Notification for creating a templates folder

The same request will be displayed every time you open a folder with a solution file which does not yet have the .vscode/solution-explorer folder with template files created.

- You can now right-click on the solution node in the Solution Explorer and invoke the Add new project command. It will list the templates provided by the dotnet command.

list-of-available-project-templates

Figure 5: List of available project templates

After selecting the language (C#, F# or VB) and entering the name, it will again execute the dotnet command with parameters corresponding to your choices:

dotnet new mvc -lang C# -n Application -o Application

- New files can now be created by right-clicking the project or a folder inside it and invoking the Create file command. You will need to enter a filename (including its extension, e.g. .cs) and select one of the templates which were previously created in the .vscode/solution-explorer folder.

available-file-templates

Figure 6: List of available file templates

As soon as you open the first C# code file in the editor, the C# extension will offer to generate build tasks and launch configurations for your project.

notification-for-creating-build-debug-assets

Figure 7: Notification for creating build and debug assets

These tasks will allow you to quickly build your project using the standard Ctrl+Shift+B keyboard shortcut, and more importantly to run and debug the project using the F5 keyboard shortcut.

Similar to Visual Studio (VS), it will start the application. In case of a web application, it will also open the start page in your default browser. It will automatically attach the debugger to the .NET Core application process. The execution will stop at breakpoints you place in the code, allowing you to look at the current program state.

debugging-dotnet-core-application

Figure 8: Debugging a .NET Core application

Working with Unit Tests

Unit tests are an important part of software development.

A test project can be created in the solution folder following the same steps as when creating the application project. You just need to select the correct project template (Unit test project or xUnit test project, depending on the test framework you want to use).

Once the test project is created, you can reference the application project from it using the Solution Explorer Add reference command from the project context menu. With only two projects in the solution, the application project will automatically be added as a reference. If there were more projects, you would have to select one from the list.

project-reference-solution-explorer-view

Figure 9: Project reference in the Solution Explorer view

To simplify running the unit tests and viewing the results, you should install another extension, .NET Core Test Explorer.

It provides several testing related functionalities:

- A new side bar view resembling the Test Explorer in Visual Studio (hence the name) and a corresponding icon in the activity bar (i.e. the vertical bar with icons for different side bar views) to access it.

dotnet-test-explorer-side-bar-view

Figure 10: .NET Test Explorer side bar view

It lists all the tests in a tree view, grouped by namespace and class, along with the results of the latest test run. Each test can be navigated to using the Go to Test command in its context menu. Tests can be run from here at each hierarchy level: individually, by class, by namespace, or all of them.

- The latest test outcome for each test method in its Code Lens.

test-outcome-code-lens

Figure 11: Test outcome in Code Lens

There’s a command for running and debugging individual tests added to Code Lens as well. The latter is very useful for troubleshooting failing tests.

- Failed tests listed as problems for the files in which they are contained.

failed-test-treated-problem

Figure 12: Failed test treated as a problem

The extension currently supports only a single test project inside the folder open in Visual Studio Code. If it finds more than one during auto-discovery, all the features will not work correctly.

There’s an open issue in GitHub to add proper support for multiple test projects. Until it gets resolved, the problem can be partially worked around by specifying the path to the test project as a workspace setting.

To do so, open the settings editor via the File > Preferences > Settings menu item, click the Workspace settings tab and add the following line:

"dotnet-test-explorer.testProjectPath": "./Tests"

This will not make the extension work with multiple test projects, but will restrict it to only process the test project inside the given folder. As long as there is only a single test project in that folder, the extension will function correctly with that test project and ignore any other test projects in the solution.

This way you’ll be able to use it with one test project instead of not using it at all.

Continuous Testing

In my previous article Continuous Testing in .NET, I described how continuous testing for .NET Core can be configured using a command line tool. Although the .NET Core Test Explorer extension has some built-in support for continuous testing, i.e. auto running of tests whenever any source file changes, it still depends on the same command line tool.

Therefore, to get it working, you first need to add the tool reference to the test project. You can open the test project file from its context menu in the Solution Explorer view. The following line must be added inside the ItemGroup element which already contains other PackageReference and DotNetCliToolReference elements:

<DotNetCliToolReference Include="Microsoft.DotNet.Watcher.Tools" Version="2.0.2" />

This will make the dotnet watch command available to the extension. To enable the continuous testing auto watch mode in the extension, you also need to add the following entry to the workspace settings:

"dotnet-test-explorer.autoWatch": true

After changing the setting, you need to reinitialize the extension by clicking the Refresh button in the top right corner of its side bar view. Once it discovers the tests in the project, it will start the dotnet watch command line tool to watch for changes and automatically rerun the tests when a change is detected.

Code Coverage

Recently, a code coverage library for .NET Core was released, named Coverlet. By referencing it from the test project, the code coverage results can also be displayed inside Visual Studio Code.

First, you need to add the coverlet.msbuild NuGet package to the test project. You can use the Add package command from the Solution Explorer context menu.

To calculate the code coverage during the test run, you would need to add additional arguments to the command line which is used to run the tests.

Unfortunately, as of now you can’t change the command which the Test Explorer extension is using to run the tests. However, the extension will still pick up and show the test results if they are output to the same file that the extension itself is using.

This allows us to use a Visual Studio Code task to run the tests with the required command line arguments and have the Test Explorer still pick up and show the results.

Let’s configure it.

If you look at the Test Explorer output in the Visual Studio Code Output window after the extension starts watching for the changes, you can find the command which was executed, e.g.:

d:\Users\Damir\Temp\VsCodeDotNetCore> d:\Users\Damir\Temp\VsCodeDotNetCore\Tests
d:\Users\Damir\Temp\VsCodeDotNetCore\Tests> dotnet watch test --logger "trx;LogFileName=C:\Users\Damir\AppData\Local\Temp\test-explorer-3rLrRb\Results.trx"

As you can see, the results file is placed in a temporary folder. You can change that by configuring a workspace setting:

"dotnet-test-explorer.pathForResultFile": "./.vscode/test-results"

The folder must exist prior to running the command, otherwise it will fail. Although the extension will take the setting into account, it will unfortunately still create a temporary folder inside the folder specified which will change every time Visual Studio Code is restarted:

d:\Users\Damir\Temp\VsCodeDotNetCore> d:\Users\Damir\Temp\VsCodeDotNetCore\Tests
d:\Users\Damir\Temp\VsCodeDotNetCore\Tests> dotnet test --logger "trx;LogFileName=d:\Users\Damir\Temp\VsCodeDotNetCore\.vscode\test-results\test-explorer-WkEF31\Results.trx"

You can still configure a task for continuously running the tests in .vscode/tasks.json which will run the above command, but with the additional arguments needed for Coverlet:

{
    "label": "test",
    "command": "dotnet",
    "type": "process",
    "options": {
        "cwd": "${workspaceFolder}/Tests"
    },
    "args": [
        "watch",
        "test",
        "--logger",
        "\"trx;LogFileName=../.vscode/test-results/test-explorer-WkEF31/Results.trx\"",
        // Coverlet arguments
        "/p:CollectCoverage=true",
        "/p:CoverletOutputFormat=lcov",
        "/p:CoverletOutput=./lcov"
    ],
    "problemMatcher": "$msCompile",
    "group": {  // set the task as the default test task
        "kind": "test",
        "isDefault": true
    }
}

Apart from enabling Coverlet, the newly added arguments also specify its output format and result file so that a Visual Studio Code extension will be able to read it. The group property is used to make this task the default task in Visual Studio Code so that it can be run by the Run Test Task command.

To display the code coverage information in Visual Studio Code, install the Coverage Gutters extension. It works with files in any language if the coverage information is available in one of its supported formats.

With the latest change in the task configuration, a lcov.info file will be generated in the test project folder on every test run. You can enable the Coverage Gutters extension to watch for that file by clicking on the Watch button in the left part of the status bar.

image

Figure 13: Coverage Gutters Watch button in status bar

This will cause the coverage information to automatically refresh in the code editor windows as the tests are continuously running in the background.

code-coverage-information-code-editor-window

Figure 14: Code coverage information in the code editor window

You will still need to run the task in tasks.json once to start the watcher. Since this task is configured as the default test task, you can invoke it with the special Tasks: Run Test Task command in Visual Studio Code. Since there’s no shortcut configured for this command out-of-the-box and it’s not included in any menu, you can only invoke it from the Command palette.

To make it more accessible, you can give it the same shortcut as in Visual Studio by adding the following to your keyboard shortcuts file keybindings.json:

{
    "key": "ctrl+r t",
    "command": "workbench.action.tasks.test"
}

Whenever you save one of the files from now on, the tests will automatically re-run. To stop the watcher, you will need to invoke the Tasks: Terminate Task command. It also has no shortcut configured by default.

It’s also a good idea to disable the Test Explorer auto watch mode when using your own task to avoid running the tests twice and prevent any conflicts that could occur because of that.

The path for the results file in the build task will need to be modified on every restart of Visual Studio Code, which makes this solution less than ideal, but it’s still the best I could come up with using the tools that are currently available.

Deployment to Azure

Microsoft Azure is Microsoft’s cloud computing platform. One of the many services it provides is Azure App Service which can be used for hosting web applications.

Web application deployment will typically take place on the build server as a part of the continuous deployment configuration. However, for testing purposes, you sometimes might want to deploy your application manually. If your deployment target is an Azure App Service, the Azure App Service extension for Visual Studio Code could prove useful.

Once installed, it adds its own side bar view and a corresponding icon in the activity bar.

Before you’ll be able to use it, you’ll need to sign into your Azure account using the standard interface provided by the Azure Account extension which gets automatically installed as an extension dependency. Clicking the Sign in to Azure… button in the Azure App Service side bar view will open a notification with short instructions.

azure-account-extension-sihn-in-notification

Figure 15: Azure Account extension sign-in notification

The button will open a web page where you will paste the code provided and sign into your selected Azure account. After you do that, you will be able to explore the Azure app services you have access to, grouped by subscription.

azure-app-service-tree-view-vscode

Figure 16: Azure App Service tree view in Visual Studio Code

The Azure App Service extension features are mostly focused on deployment of Node.js applications, but when used correctly, it can also be used for deploying ASP.NET Core web applications.

Since the extension doesn’t have any awareness of the solution and project structure, you’ll first need to create a publish folder for the project you want to deploy. You can use the Publish command in the Solution Explorer context menu for that.

The path to the folder will typically be the bin/Debug/netcoreapp2.0/publish subfolder inside the project folder, but it will also be listed at the end of the Solution Explorer output in the Visual Studio Code Output window after the command completes.

You’re now ready to start the extension’s deployment wizard by clicking the Deploy to Web App button in the top right corner of the side bar view. Following its steps, you will enter all the required information:

  • path to the publish folder (click the Browse option in the dropdown list to select the folder),
  • Azure subscription,
  • web app (you can select an existing one or create a new one),
  • web app name (only when creating a new web app),
  • resource group (only when creating a new web app, you can select an existing one or create a new one),
  • resource group name (only when creating a new resource group),
  • operating system (only when creating a new web app),
  • app service plan (only when creating a new web app, you can select an existing one or create a new one),
  • app service plan name (only when creating a new plan),
  • pricing tier (only when creating a new plan, only a subset of available tiers will be listed, you will need to create the app service plan in the portal to have all the tiers available),
  • location (only when creating a new plan).

Upon the completion of the wizard, any newly created Azure resources will be created first. Then the contents of the selected folder will be deployed to the target Azure app service.

When the process is complete, the URL will be listed at the end of the Azure App Service output in the Visual Studio Code Output window. If you Ctrl-click it, a working web app should open in your default browser.

If it doesn’t, you can add a Files node to the Azure app service tree view for basic troubleshooting by adding the following setting to the User settings tab of the settings editor:

"appService.showRemoteFiles": true

By expanding the node for an app service, you will now see the files which were uploaded to Azure and be able to even explore their contents in the editor if you select them in the tree view.

There are other commands available in the tree view context menu, e.g. to restart or stop the service or even to delete it. Be very careful when using them if you have production services running in your Azure account.

Conclusion:

By following the instructions in this article, you can configure your free copy of Visual Studio Code to be a convenient tool for .NET Core development.

Of course, it’s not as feature rich as Visual Studio 2017, but it’s more light-weight, not limited to Windows and even cheaper. Also, judging by the improvements in the extensions and the enhancements to Visual Studio Code itself in the last two years, we can expect the .NET Core development experience to continue improving in the future.

This article was technically reviewed by Yacoub Massad.

This article has been editorially reviewed by Suprotim Agarwal.

Absolutely Awesome Book on C# and .NET

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce The Absolutely Awesome Book on C# and .NET. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

Click here to Explore the Table of Contents or Download Sample Chapters!

What Others Are Reading!
Was this article worth reading? Share it with fellow developers too. Thanks!
Share on LinkedIn
Share on Google+

Author
Damir Arh has many years of experience with software development and maintenance; from complex enterprise software projects to modern consumer-oriented mobile applications. Although he has worked with a wide spectrum of different languages, his favorite language remains C#. In his drive towards better development processes, he is a proponent of Test-driven development, Continuous Integration, and Continuous Deployment. He shares his knowledge by speaking at local user groups and conferences, blogging, and writing articles. He is an awarded Microsoft MVP for .NET since 2012.


Page copy protected against web site content infringement 	by Copyscape




Feedback - Leave us some adulation, criticism and everything in between!