dotnet / efcore

EF Core is a modern object-database mapper for .NET. It supports LINQ queries, change tracking, updates, and schema migrations.
https://docs.microsoft.com/ef/
MIT License
13.49k stars 3.13k forks source link

Update-Database -context [contextname] not working with User Secrets #28837

Closed ChesireFreeThrow closed 1 year ago

ChesireFreeThrow commented 1 year ago

I have a program with four data contexts. Everything works fine when the connection strings are coming from appsettings.json.

When I try to use the User Secrets for my connection strings, my program works and reads the connection strings fine but EF Core tools won't work. When I try to upgrade database I get the error: Value cannot be null. (Parameter 'connectionString')

Here are my connection strings in User Secrets:

{ "ConnectionStrings:SpeedContext": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=SpeedLogs;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "ConnectionStrings:EventLogContext": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ATSPM-EventLogs;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "ConnectionStrings:ConfigContext": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ATSPM-Config;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False", "ConnectionStrings:AggregationContext": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=ATSPM-Aggregation;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False" }

Once I put the connection strings back in appsettings.json update-database works fine again but the EF Tools just doesn't seem to be able to read from User Secrets???

ajcvickers commented 1 year ago

@ChesireFreeThrow Can you post the full command line and --verbose output?

ChesireFreeThrow commented 1 year ago

@ajcvickers

PM> update-database -context SpeedContext -verbose
Using project 'SignalControllerLogger'.
Using startup project 'SignalControllerLogger'.
Build started...
Build succeeded.
C:\Program Files\dotnet\dotnet.exe exec --depsfile C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\bin\Debug\net6.0\SignalControllerLogger.deps.json --additionalprobingpath C:\Users\christianbaker\.nuget\packages --additionalprobingpath "C:\Program Files (x86)\Microsoft Visual Studio\Shared\NuGetPackages" --runtimeconfig C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\bin\Debug\net6.0\SignalControllerLogger.runtimeconfig.json C:\Users\christianbaker\.nuget\packages\microsoft.entityframeworkcore.tools\6.0.7\tools\netcoreapp2.0\any\ef.dll database update --context SpeedContext --verbose --no-color --prefix-output --assembly C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\bin\Debug\net6.0\SignalControllerLogger.dll --project C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\SignalControllerLogger.csproj --startup-assembly C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\bin\Debug\net6.0\SignalControllerLogger.dll --startup-project C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\SignalControllerLogger.csproj --project-dir C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\ --language C# --configuration Debug --working-dir C:\Projects\udot-atsmp\ATSPM --root-namespace ATSPM.SignalControllerLogger
Using assembly 'SignalControllerLogger'.
Using startup assembly 'SignalControllerLogger'.
Using application base 'C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\bin\Debug\net6.0'.
Using working directory 'C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger'.
Using root namespace 'ATSPM.SignalControllerLogger'.
Using project directory 'C:\Projects\udot-atsmp\ATSPM\SignalControllerLogger\'.
Remaining arguments: .
The Entity Framework tools version '6.0.7' is older than that of the runtime '6.0.8'. Update the tools for the latest features and bug fixes. See https://aka.ms/AAc1fbw for more information.
Finding DbContext classes...
Finding IDesignTimeDbContextFactory implementations...
Finding application service provider in assembly 'SignalControllerLogger'...
Finding Microsoft.Extensions.Hosting service provider...
Using environment 'Development'.
Using application service provider from Microsoft.Extensions.Hosting.
System.ArgumentNullException: Value cannot be null. (Parameter 'connectionString')
   at Microsoft.EntityFrameworkCore.Utilities.Check.NotEmpty(String value, String parameterName)
   at Microsoft.EntityFrameworkCore.SqlServerDbContextOptionsExtensions.UseSqlServer(DbContextOptionsBuilder optionsBuilder, String connectionString, Action`1 sqlServerOptionsAction)
   at ATSPM.Infrasturcture.Extensions.ServiceExtensions.<>c__DisplayClass0_0.<AddATSPMDbContext>b__0(DbContextOptionsBuilder db) in C:\Projects\udot-atsmp\ATSPM\Infrastructure\Extensions\ServiceExtensions.cs:line 13
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass1_0`2.<AddDbContext>b__0(IServiceProvider p, DbContextOptionsBuilder b)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.CreateDbContextOptions[TContext](IServiceProvider applicationServiceProvider, Action`2 optionsAction)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__DisplayClass17_0`1.<AddCoreServices>b__0(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.EntityFrameworkServiceCollectionExtensions.<>c__17`1.<AddCoreServices>b__17_1(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitIEnumerable(IEnumerableCallSite enumerableCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetServices[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextTypes()
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.FindContextType(String name)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String connectionString, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Value cannot be null. (Parameter 'connectionString')
ajcvickers commented 1 year ago

@ChesireFreeThrow Nothing obviously going wrong here. Please attach a small, runnable project or post a small, runnable code listing that reproduces what you are seeing so that we can investigate.

ChesireFreeThrow commented 1 year ago

@ajcvickers all I'm doing is trying to run update-database commands from the console while my connection strings are stored in User Secrets. It is telling me it can't find them in User Secrets so I have to move the connection strings to appsettings.json then it can find them. If you want to try to reproduce it, just try run any update-database EF commands with your connection string in User Secrets. If you can run it then I can try something different.

ajcvickers commented 1 year ago

@ChesireFreeThrow I created a default empty ASP.NET Core web application, then added a DbContext and registered it as shown in the code below. I was able to use user-secrets with it as shown:

PS C:\local\code\repros\WebApplication1\WebApplication1> dotnet user-secrets init
Set UserSecretsId to 'ac3f1866-3071-4f93-81f3-a7e7053ed10b' for MSBuild project 'C:\local\code\repros\WebApplication1\WebApplication1\WebApplication1.csproj'.
PS C:\local\code\repros\WebApplication1\WebApplication1> dotnet user-secrets set ConnectionStrings:MyConnectionString "Data Source=(LocalDb)\MSSQLLocalDB;Database=MyDb"          
Successfully saved ConnectionStrings:MyConnectionString = Data Source=(LocalDb)\MSSQLLocalDB;Database=MyDb to the secret store.
PS C:\local\code\repros\WebApplication1\WebApplication1> dotnet ef migrations add One
Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.6 initialized 'SomeDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.6' with options: None
Done. To undo this action, use 'ef migrations remove'
PS C:\local\code\repros\WebApplication1\WebApplication1> dotnet ef database update           
Build started...
Build succeeded.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.6 initialized 'SomeDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.6' with options: None
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (135ms) [Parameters=[], CommandType='Text', CommandTimeout='60']
      CREATE DATABASE [MyDb];
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (42ms) [Parameters=[], CommandType='Text', CommandTimeout='60']
      IF SERVERPROPERTY('EngineEdition') <> 5
      BEGIN
          ALTER DATABASE [MyDb] SET READ_COMMITTED_SNAPSHOT ON;
      END;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE [__EFMigrationsHistory] (
          [MigrationId] nvarchar(150) NOT NULL,
          [ProductVersion] nvarchar(32) NOT NULL,
          CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
      );
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [MigrationId], [ProductVersion]
      FROM [__EFMigrationsHistory]
      ORDER BY [MigrationId];
info: Microsoft.EntityFrameworkCore.Migrations[20402]
      Applying migration '20220912104236_One'.
Applying migration '20220912104236_One'.
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE [Blogs] (
          [Id] int NOT NULL IDENTITY,
          CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id])
      );
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
      VALUES (N'20220912104236_One', N'6.0.6');
Done.
PS C:\local\code\repros\WebApplication1\WebApplication1>
using Microsoft.EntityFrameworkCore;
using WebApplication1;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddDbContext<SomeDbContext>(b =>
{
    b.UseSqlServer("Name=MyConnectionString");
});

var app = builder.Build();

app.MapGet("/", () => "Hello World!");

app.Run();
using Microsoft.EntityFrameworkCore;

namespace WebApplication1;

public class SomeDbContext : DbContext
{
    public SomeDbContext(DbContextOptions<SomeDbContext> options)
        : base(options)
    {
    }

    public DbSet<Blog> Blogs => Set<Blog>();
}

public class Blog
{
    public int Id { get; set; }
}
ChesireFreeThrow commented 1 year ago

@ajcvickers Thank you very much for trying that out. The only difference is you did the "dotnet ef database update" command and I did "update-database" because I'm using the Microsoft.EntityFrameworkCore.Tools nuget package to run the commands. Maybe the problem is with that?

ajcvickers commented 1 year ago
Package Manager Console Host Version 6.3.0.131

Type 'get-help NuGet' to see all available NuGet commands.

PM> Add-Migration Two
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.6 initialized 'SomeDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.6' with options: None
To undo this action, use Remove-Migration.
PM> Update-Database
Build started...
Build succeeded.
Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.6 initialized 'SomeDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer:6.0.6' with options: None
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (12ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (8ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT 1
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (0ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT OBJECT_ID(N'[__EFMigrationsHistory]');
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (2ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT [MigrationId], [ProductVersion]
      FROM [__EFMigrationsHistory]
      ORDER BY [MigrationId];
Microsoft.EntityFrameworkCore.Migrations[20402]
      Applying migration '20220912132640_Two'.
Applying migration '20220912132640_Two'.
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      ALTER TABLE [Blogs] ADD [Name] nvarchar(max) NOT NULL DEFAULT N'';
Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (1ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
      VALUES (N'20220912132640_Two', N'6.0.6');
Done.
PM> 
ChesireFreeThrow commented 1 year ago

Looks like something else is causing my problem. No idea what. But thanks for your help. The only thing I'm doing differently is I have four database contexts in my project.