.net-coreentity-framework-coreentity-framework-migrations

.NET Entity Framework Core database update fails with "Host can't be null"


I have a new ASP.NET Core Web API project that I'm trying to get set up with Entity Framework Core.

I did my initial migrations and it successfully created a migration class in the Migrations folder.

I tried to then update the database:

dotnet ef database update      

and it fails with:

dotnet ef database update
Build started...
Build succeeded.

System.ArgumentException: Host can't be null

at Npgsql.NpgsqlConnectionStringBuilder.PostProcessAndValidate()
at Npgsql.NpgsqlConnection.SetupDataSource()
at Npgsql.NpgsqlConnection.set_ConnectionString(String value)
at Npgsql.NpgsqlConnection..ctor(String connectionString)
at Npgsql.NpgsqlConnection.CloneWith(String connectionString)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlRelationalConnection.CloneWith(String connectionString)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlDatabaseCreator.Exists(Boolean async, CancellationToken cancellationToken)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlDatabaseCreator.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.GetAppliedMigrations()
at Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Internal.NpgsqlMigrator.Migrate(String targetMigration)
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)

Host can't be null

I have found a few posts from years ago with this issue but none of them had a solution.

Program.cs:

using Microsoft.EntityFrameworkCore;
using ShopBack.Services;
    
var builder = WebApplication.CreateBuilder(args);

builder.Services
       .AddScoped<ProductsService>()  
       .AddControllers(options => options.SuppressAsyncSuffixInActionNames = false);
        
builder.Services.AddDbContext<LibraryContext>(options =>
        {
            options.UseNpgsql(builder.Configuration.GetConnectionString("YourConnectionName"));
        });
    
var app = builder.Build();

// configure request pipeline
app.MapControllers();
    
app.UseCors (x => x
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());
    
app.Run();

appsettings.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "YourConnectionName": "Host=127.0.0.1; Port=5432; User Id=postgres; Password=postgres; Database=shopback"
  }
}

appsettings.Development.json:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "YourConnectionName": "Host=127.0.0.1; Port=5432; User Id=postgres; Password=postgres; Database=shopback"
  }
}

.csproj:

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.7">
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
      <PrivateAssets>all</PrivateAssets>
    </PackageReference>

    <PackageReference Include="Npgsql" Version="8.0.3" />

    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.4" />

  </ItemGroup>

  <ItemGroup>
    <None Update="appsettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
  </ItemGroup>

</Project>

Solution

  • As per Michal's comment, I added a --connection parameter with my connection information:

    dotnet ef database update --connection "Host=127.0.0.1; Port=5432; User Id=postgres; Password=postgres; Database=shopback"
    

    And the database update command worked and my tables have been created.

    I did find this updates page talking about the new --connection parameter:

    https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-5.0/whatsnew#new-command-line-parameters-for-namespaces-and-connection-strings

    But it says the new --connection is now available in EF Core 5.0 not that the --connection is the only way to have Entity Framework Core get your connection.

    Why wouldn't it pull this from my project's appsettings.json file?

    UPDATE I found the issue. With Entity you create a context class that inherits from DbContext and this is where you define what your tables will look like. My class I use for this is called "LibraryContext" and in my "OnConfiguring" method when I am referencing my connection string I referenced it incorrectly because I was working from examples I found online. See the below code where the incorrect configuration is commented out right above the correct configuration for the connection string.

    using Microsoft.EntityFrameworkCore;
    
    public class LibraryContext : DbContext
    {
        public LibraryContext(DbContextOptions<LibraryContext> options) : base(options){}
        public DbSet<Item> Items { get; set; }
        public DbSet<Category> Categories { get ; set; }
    
    
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
                .AddJsonFile("appsettings.json")
                .Build();
               // optionsBuilder.UseNpgsql(configuration.GetConnectionString("Database:ConnectionStrings:YourConnectionName"));
                optionsBuilder.UseNpgsql(configuration.GetConnectionString("YourConnectionName"));
        }
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            //configure the Item table
            modelBuilder.Entity<Item>().ToTable("Item");
    
            modelBuilder.Entity<Item>()
                .HasKey(b => b.Id);
    
            modelBuilder.Entity<Item>()
                .Property(i => i.Name)
                .HasMaxLength(100)
                .IsRequired();
    
            modelBuilder.Entity<Item>()
                .HasOne(b => b.Category)
                .WithMany(c => c.Items)
                .HasForeignKey(b => b.CategoryId)
                .IsRequired();
    
            //configure the category table
            modelBuilder.Entity<Category>().ToTable("Category");
    
            modelBuilder.Entity<Category>()
                .HasKey(c => c.Id);
    
            modelBuilder.Entity<Category>()
                .Property(c => c.Name)    
                .HasMaxLength(100)
                .IsRequired();
        }
    
    }
    

    and once again here is my appsettings.json file. The incorrect reference above would expect the json file to be formatted a bit differently.

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "YourConnectionName": "Host=127.0.0.1; Port=5432; User Id=postgres; Password=postgres; Database=shopback"
      }
    }