Tuesday, January 28, 2020

Apparent Bug in the Visual Studio Code Debugger / .NET Core CLI

So I ran into some weirdness with a project. It runs fine in the Visual Studio 2019 debugger but throws a runtime exception in the Visual Studio Code debugger. The application builds fine from Visual Studio 2019, Visual Studio Code, and "dotnet build". These executables run fine on their own. But running the application with "dotnet run" or from Visual Studio Code results in the exception.

I have .NET Core SDK version 3.1.101 installed (the current at the time of this article).

Summary
  • Debug from Visual Studio 2019: SUCCESS
  • Debug from Visual Studio Code: FAILURE
  • Run from executable (VS or CLI build): SUCCESS
  • Run from Visual Studio Code: FAILURE
  • Run from CLI (dotnet run): FAILURE
This impacts a particular project that uses EFCore / SQLite. I'm guessing that there's something weird in the CLI tools since the Visual Studio 2019 debugger works fine.

The code is available in GitHub: 04-DynamicLoading-Plugin (on the "UsingWorkingDirectory" branch). The specific project is the "PeopleViewer" project. See below for sample runs.

Update 29 Jan 2020
I was able to track down the issue. When looking at code changes in Git, I noticed that running the code in Visual Studio Code or the CLI (dotnet run) created a People.db file in the project folder. This file is normally in the executable folder. This leads me to the following:
Visual Studio 2019 debugger uses the executable folder as the working directory.
Visual Studio Code / CLI uses the project folder as the working directory.
This explains the SUCCESS/FAILURE modes listed above and the differences in behavior described in the rest of this article.

This seems like a problem to me. Even though code uses the same runtime (.NET Core 3.1), applications that work under one debugger (such as Visual Studio Code) may not work under another debugger (such as Visual Studio).

Also, for those who are wondering why the sample application uses files loaded from a directory, the same behavior is exhibited in an application with compile-time links. This sample project is available on GitHub: 03-Extensibility (also on the "UsingWorkingDirectory" branch).

I'll leave it up to the tool developers to decide where the problem actually lies. But this looks like a bug to me.

End Update

Update 5 Feb 2020: The working directory for Visual Studio Code can be changed from the default value in the "launch.json" file (Thanks to Craig in the comments; I overlooked this). Additional information: Set the Working Directory in Visual Studio Code (or better yet, eliminate the requirement on the working directory).

Successful Run
The project runs fine from Visual Studio 2019.

Open "DynamicLoading.sln".


"Start Debugging" the PeopleViewer project.


The application starts up.


Click the "Dynamic Reader" button. (It takes a few seconds for the SQL DB stuff to spin up the first time.)


SUCCESS!
The data is displayed and a popup shows that it is using the SQL data reader.

This same scenario works when we run the executable from File Explorer.


Running the project from the "bin/Debug/netcore31" folder gives the same results.

Failure Run
The project fails in Visual Studio Code.

Open the "PeopleViewer" folder in Visual Studio Code.


From the "Debug" menu, choose "Start Debugging".


The application starts up.


Clicking the "Dynamic Reader" button results in an exception.


FAILURE!
The exception comes from SQLite. The error is "no such table: People".

So it can find the table in the Visual Studio 2019 debugger, but not the Visual Studio Code debugger.

Other Tests
Here's what happens from the CLI.

Navigate PowerShell to the "PeopleViewer" folder. And type "dotnet build".


The build succeeds.


Type "dotnet run" to run the application.


The application starts successfully.


But clicking the "Dynamic Reader" button results in a run-time exception and the application exits.


Navigate to the output folder "PeopleViewer\bin\Debug\netcoreapp3.1"


Then run the application directly with ".\PeopleViewer.exe"


The application starts.


Clicking "Dynamic Reader" works.


This tells me that the builds are fine. There is something wrong with the CLI debugger and CLI runner.

One last test is to run the application in Visual Studio Code without debugging. In Visual Studio Code, choose "Debug / Start Without Debugging".


The application starts.


Clicking the "Dynamic Reader" button shuts down the application. The terminal window in Visual Studio Code show the same "no such table: People" error.


Wrap Up
Trying to run the application in these different ways leads me to believe that there is something wrong with the CLI runner and/or the Visual Studio Code debugger.

The Visual Studio 2019 debugger runs the application fine. The compiled application from Visual Studio 2019 runs fine from File Explorer.

Visual Studio Code and the CLI "dotnet build" do not appear to be the problem. The generated executable runs fine.

"dotnet run" seems to be culprit. This looks like a bug to me, but I'm not exactly sure how to report it. I'm working on how to get the right person to look at it, and I'll be sure to post any updates here.

2 comments:

  1. Great post, I just ran into this issue myself and it helped me resolve it.
    My SQLite.db file was being created in my root workspace folder (as a pose to the project folder)
    A quick look at my launch.json file in {root}/.vscode/launch.json and there is this cwd setting.
    "cwd": "${workspaceFolder}"
    I updated it to match the folder in the program setting.
    "cwd": "${workspaceFolder}/src/CraigProject3/bin/Debug/netcoreapp3.1"
    and it works as expected now! Thanks!

    ReplyDelete
    Replies
    1. Thanks Craig. I did not think to look in the launch.json settings. I ended up changing the SQLite configuration string to include the entire path to the db file: $"Data Source={AppDomain.CurrentDomain.BaseDirectory}People.db".
      I wrote an article about it, too: https://jeremybytes.blogspot.com/2020/02/set-working-directory-in-visual-studio.html

      Delete