postgresql.net-coreentity-framework-core

MSB4057: The target "GetEFProjectMetadata" does not exist in the project. .NET Core 8, Entity Framework Core 8


The Problem

I'm trying to setup Entity Framework Core 8 to use PostgreSQL and cannot do the initial migration. I am doing this on my local Windows machine - not a build server.

I am able to download the EntityFramework.Docs repository from GitHub and modify and generate migrations just fine using dotnet ef migrations add TestMigration, so I am 99% confident that the correct tooling is installed.

But I get the following error when I try to do so in my actual solution:

error MSB4057: The target "GetEFProjectMetadata" does not exist in the project.

Microsoft.EntityFrameworkCore.Tools.CommandException: Unable to retrieve project metadata. Ensure it's an SDK-style project. If you're using a custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath option.

at Microsoft.EntityFrameworkCore.Tools.Project.FromFile(String file, String buildExtensionsDir, String framework, String configuration, String runtime)
at Microsoft.EntityFrameworkCore.Tools.RootCommand.Execute(String[] _)
at Microsoft.EntityFrameworkCore.Tools.Commands.CommandBase.<>c__DisplayClass0_0.b__0(String[] args)
at Microsoft.DotNet.Cli.CommandLine.CommandLineApplication.Execute(String[] args)
at Microsoft.EntityFrameworkCore.Tools.Program.Main(String[] args)

Unable to retrieve project metadata. Ensure it's an SDK-style project. If you're using a custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath option.

Because of how my company structures solutions, I have the following projects:

Originally, I tried running

dotnet ef migrations add InitializeDB --project src/PostgreSQL --startup-project src/Web

and I got the error above.

So, I added the PostgreSQL.Host project so I can try different ways of initializing the DbContext - since some posts stated that might be the cause of the issue.

No matter what I've tried, I get the same error.

Things I've tried:

Relevant source files

dotnet ef returns

Entity Framework Core .NET Command-line Tools 8.0.8

MyDbContext looks like this:

public class MyDbContext : DbContext
{
    public MyDbContext (DbContextOptions<MyDbContext > options)
        : base(options)
    { }
    // ...
}

MyDesignTimeDbContextFactory looks like this:

// This can be removed, if not needed.
public class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
    public MyDbContext CreateDbContext(string[] args)
    {
            // Build configuration
            IConfigurationRoot configuration = new ConfigurationBuilder()
                .SetBasePath(Directory.GetCurrentDirectory())
                .AddJsonFile("../Host.Web/appsettings.json")
                .Build();

            // Get connection string
            var connectionString = configuration.GetSection("PostgreSQLSettings")["ConnectionString"];

            // Configure DbContext options
            var optionsBuilder = new DbContextOptionsBuilder<MyDbContext>();
            optionsBuilder.UseNpgsql(connectionString);

            return new MyDbContext(optionsBuilder.Options);
    }
}

PostgreSQL.csproj looks like this:

<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <RootNamespace>MyProject.PostgreSQL</RootNamespace>
        <Nullable>enable</Nullable>
        <OutputType>Library</OutputType>
        <TargetFramework>net8.0</TargetFramework>
    </PropertyGroup>
    <ItemGroup>
        <PackageReference Include="Microsoft.EntityFrameworkCore.Design">
          <PrivateAssets>all</PrivateAssets>
          <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
        </PackageReference>
        <PackageReference Include="Microsoft.Extensions.Configuration.Binder" />
        <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
        <PackageReference Include="Ulid" />
        <ProjectReference Include="..\Core\Core.csproj" />
    </ItemGroup>

    <ItemGroup>
      <PackageReference Include="Microsoft.Extensions.Hosting" />
    </ItemGroup>
</Project>

This is PostgreSQL.Host.csproj:

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

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

  <ItemGroup>
    <ProjectReference Include="..\PostgreSQL\PostgreSQL.csproj" />
  </ItemGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design">
      <PrivateAssets>all</PrivateAssets>
      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
    </PackageReference>
    <PackageReference Include="Microsoft.Extensions.Hosting" />
  </ItemGroup>
</Project>

Command run is variations on

dotnet ef migrations add InitializeDB --project src/PostgreSQL --startup-project src/PostgreSQL.Host --verbose

Error:

Error MSB4057: The target "GetEFProjectMetadata" does not exist in the project.

Microsoft.EntityFrameworkCore.Tools.CommandException: Unable to retrieve project metadata. Ensure it's an SDK-style project. If you're using a custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath option.

at Microsoft.EntityFrameworkCore.Tools.Project.FromFile(String file, String buildExtensionsDir, String framework, String configuration, String runtime)
at Microsoft.EntityFrameworkCore.Tools.RootCommand.Execute(String[] _)
at Microsoft.EntityFrameworkCore.Tools.Commands.CommandBase.<>c__DisplayClass0_0.b__0(String[] args)
at Microsoft.DotNet.Cli.CommandLine.CommandLineApplication.Execute(String[] args)
at Microsoft.EntityFrameworkCore.Tools.Program.Main(String[] args)

Unable to retrieve project metadata. Ensure it's an SDK-style project. If you're using a custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath optio

Any suggestions on what I'm doing wrong?

Thanks.

UPDATE

The solution has a Dicretory.Build.props file that includes:

<RepoRoot Condition="$(RepoRoot) == ''">$([MSBuild]::EnsureTrailingSlash('$(MSBuildThisFileDirectory)'))</RepoRoot>
<ArtifactsPath>$(RepoRoot)artifacts</ArtifactsPath>

If I remove the ArtifactsPath line then the migration works.

I can't remove that line because that breaks other things in the solution build process.

So, I need to work around that setting.

I've tried setting the --msbuildprojectextensionspath to that artifacts folder manually, but it doesn't work.

Any ideas?


Solution

  • I figured out how to solve this.

    Create an entity host/migrations project - the purpose of which is only to create migrations.

    In that project, add a new Directory.Build.props file that looks like this:

    <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <!-- 
        This file must exist in the project folder in order to override the solution level Directory.Build.props file.
        Otherwise, the changes to the ArtifactsPath breaks the `dotnet ef migrations add` command.
       -->
    </Project>
    

    Now you can run your dotnet ef migrations add commands.