dotnet / dotnet/project-system

Default working directory inconsistent between dotnet run and Visual Studio

Open
#3,619 19 comments 38 reactions 1 assignee Claimed by @tmeschter View on GitHub
Feature-Debugging Triage-Investigate
Dominant language
C#
Stars
1k
Forks
415
PR merge metrics
No merged PRs in 30d

Description

(first reported at https://github.com/aspnet/EntityFramework.Docs/issues/735)

It seems that there was a decision in https://github.com/dotnet/project-system/issues/2239 to change the current directory to be the output directory.

I am not sure about the rationale or what the behavior was before, but what I am seeing is that (using .NET Core SDK 2.1.300, .NET Core 2.1 and Visual Studio 2017 15.7.3), the default working directory is inconsistent between executing an application in Visual Studio (using F5 or Ctrl+F5), which results in the working directory set to the output directory, and other ways, which use the project folder, like dotnet run, dotnet ef migrations commands in the CLI and even the EF Core migration tools that run in the Package Manager Console inside Visual Studio.

I am aware that it is possible to explicitly set the working directory to an absolute path using Visual Studio and that this is recorded in launch settings, which other tools pick up. This issue is about the default behavior when the working directory is not explicitly configured.

To repro, it is enough to just create a simple application that prints Directory.GetCurrentDirectory().

Here are the repro steps that shows how this impacts the location of an application's SQLite database file (based on the walkthrough at https://docs.microsoft.com/en-us/ef/core/get-started/netcore/new-db-sqlite):

Create a new console app from the command line:

``` console
mkdir ConsoleApp.SQLite
cd ConsoleApp.SQLite/
dotnet new console
```

Add the following EF Core packages:

``` console
dotnet add package Microsoft.EntityFrameworkCore.Sqlite
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Microsoft.EntityFrameworkCore.Tools
```
(the latter is only necessary to repro the inconsistency with PMC)

Add the following sample model into Model.cs:

``` csharp

using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace ConsoleApp.SQLite
{
public class BloggingContext : DbContext
{
public DbSet Blogs { get; set; }
public DbSet Posts { get; set; }

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source=blogging.db");
}
}

public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }

public List Posts { get; set; }
}

public class Post
{
public int PostId { get; set; }
public string Title { get; set; }
public string Content { get; set; }

public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}
```

Add the following code into Program.cs:

``` csharp
using System;
using System.IO;

namespace ConsoleApp.SQLite
{
public class Program
{
public static void Main()
{
Console.WriteLine(Directory.GetCurrentDirectory());
using (var db = new BloggingContext())
{
db.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
var count = db.SaveChanges();
Console.WriteLine("{0} records saved to database", count);
Console.WriteLine();
Console.WriteLine("All blogs in database:");
foreach (var blog in db.Blogs)
{
Console.WriteLine(" - {0}", blog.Url);
}
}
}
}
}

```

Execute the following commands to create the database:

``` console
dotnet ef migrations add InitialCreate
dotnet ef database update
```

Note that the database was created in the project directory.

Executing the application from the command line results in this output.

``` console
ConsoleApp.SQLite>dotnet run
C:\Users\myself\source\repos\ConsoleApp.SQLite
1 records saved to database

All blogs in database:
- http://blogs.msdn.com/adonet
```

Now try to execute the application from Visual Studio (F5 or Ctrl+F5). The output shows an exception indicating that the table doesn't exist. That is because opening a connection with a database file that doesn't exist creates an empty database file:

``` console
C:\Users\myself\source\repos\ConsoleApp.SQLite\bin\Debug\netcoreapp2.1

Unhandled Exception: Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> Microsoft.Data.Sqlite.SqliteException: SQLite Error 1: 'no such table: Blogs'.
at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements(Stopwatch timer)+MoveNext()
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.Execute(IRelationalConnection connection, DbCommandMethod executeMethod, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
--- End of inner exception stack trace ---
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.Execute(IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(DbContext _, ValueTuple`2 parameters)
at Microsoft.EntityFrameworkCore.Storage.Internal.NoopExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.Execute(IEnumerable`1 commandBatches, IRelationalConnection connection)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(IReadOnlyList`1 entriesToSave)
at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChanges(Boolean acceptAllChangesOnSuccess)
at Microsoft.EntityFrameworkCore.DbContext.SaveChanges(Boolean acceptAllChangesOnSuccess)
at ConsoleApp.SQLite.Program.Main() in C:\Users\myself\source\repos\ConsoleApp.SQLite\Program.cs:line 14
```

Now, let's try to update the database using the EF Core PMC commands. First, drop the database from the OS command-line to make sure we will observe the default behavior of the PMC commands:

``` console
C:\Users\myself\source\repos\ConsoleApp.SQLite>dotnet ef database drop --force
```

Switch to the Package Manager Console inside Visual Studio, type:

``` console
PM> update-database -verbose
```

You will see that one of the last lines indicates:

``` console
Closing connection to database 'main' on server 'C:\Users\myself\source\repos\ConsoleApp.SQLite\blogging.db'.
```

cc @bricelam

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.