PabloChristian
PabloChristian

Reputation: 57

NET 5 error when adding migration on Entity Framework Core

I'm setting up a new project with Entity Framework Core 5 and Postgres. All my project and my context are in the same project.

When adding a migration, I'm getting this error:

/src/Api.csproj : error MSB4057: The target "GetEFProjectMetadata" does not exist in the project. Unable to retrieve project metadata. Ensure it's an MSBuild-based .NET Core project. If you're using custom BaseIntermediateOutputPath or MSBuildProjectExtensionsPath values, Use the --msbuildprojectextensionspath option.

EF Core version: 5.0.1 Target framework: net5.0

These are all the commands I tried:

dotnet ef migrations add NewMigration

dotnet ef migrations add NewMigration --msbuildprojectextensionspath     

dotnet ef migrations add NewMigration -p ".\src\Api.csproj"

dotnet ef migrations add NewMigration -p ".\src\Api.csproj" --msbuildprojectextensionspath*     

I have tried a lot of options I found on the internet, but none worked.

if i add -v , the last lines are:

Using project '/media/pablo/l/Projetos/Web/backend/boilerplate/dotnet_csharp/src/Api.csproj'.
Using startup project '/media/pablo/l/Projetos/Web/backend/boilerplate/dotnet_csharp/src/Api.csproj'.
Writing '/media/pablo/l/Projetos/Web/backend/boilerplate/dotnet_csharp/src/obj/Api.csproj.EntityFrameworkCore.targets'...
dotnet msbuild /target:GetEFProjectMetadata /property:EFProjectMetadataFile=/tmp/tmpbscOwZ.tmp /verbosity:quiet /nologo /media/pablo/l/Projetos/Web/backend/boilerplate/dotnet_csharp/src/Api.csproj
/media/pablo/l/Projetos/Web/backend/boilerplate/dotnet_csharp/src/Api.csproj : error MSB4057: O destino "GetEFProjectMetadata" não existe no projeto.
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.<Configure>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.

Api.csproj:

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

  <PropertyGroup>
    <TargetFramework>net5.0</TargetFramework>
    <DocumentationFile>bin\Debug\net5.0\comments.xml</DocumentationFile>
    <GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
    <noWarn>1591;1572;1573</noWarn>
    <PublishWithAspNetCoreTargetManifest>false</PublishWithAspNetCoreTargetManifest>
    <CodeAnalysisRuleSet>../roslynator.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup>
  
  <ItemGroup>
    <PackageReference Include="FluentValidation" Version="9.4.0" />
    <PackageReference Include="FluentValidation.AspNetCore" Version="9.4.0" />
    <PackageReference Include="Mapster" Version="7.0.1" />
    <PackageReference Include="Swashbuckle.AspNetCore" Version="5.5.1" />
    <PackageReference Include="Scrutor" Version="3.3.0" />
    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.1" />
    <PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.1" />
    <PackageReference Include="jaeger" Version="0.4.2" />
    <PackageReference Include="OpenTracing.Contrib.NetCore" Version="0.7.1" />
    <PackageReference Include="RestSharp" Version="106.2.1" />
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" />
    <PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="5.0.1" />
    <PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.7" />
    <PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="5.0.1" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
    <PackageReference Include="Microsoft.OpenApi" Version="1.2.3" />
    <PackageReference Include="Swashbuckle.AspNetCore.Newtonsoft" Version="5.6.3" />
  </ItemGroup>

  <ItemGroup>
    <None Include="*.json" CopyToPublishDirectory="Always" CopyToOutputDirectory="Always" />
    <None Include="Locales\**\*.json" CopyToPublishDirectory="Always" CopyToOutputDirectory="Always" />
  </ItemGroup>
</Project>

Program.cs:

using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;

namespace Linear.Service_Name.Api
{
  public static class Program
  {
    public static void Main(string[] args)
    {
      CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
      WebHost.CreateDefaultBuilder(args).UseStartup<Startup>();
  }
}

Startup.cs:

using Linear.Service_Name.DataBase.Entities;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

[assembly: Microsoft.AspNetCore.Mvc.ApiController]
namespace Linear.Service_Name.Api
{
  public class Startup
  {
    private IWebHostEnvironment _environment { get; }

    public Startup(IConfiguration _, IWebHostEnvironment environment)
    {
      _environment = environment;
    }

    public void ConfigureServices(IServiceCollection services)
    {
      services.AddDbContext<Context>(opt => opt
        .UseNpgsql(EnvVariables.LINEAR_API_DOMAIN_NAME_DB_CONNECTION_STRING)
      );
      services.AddCommonsServices<Context>(new CommonServices
      {
        Env = _environment,
        ConnectionString = EnvVariables.LINEAR_API_DOMAIN_NAME_DB_CONNECTION_STRING,
        Assembly = Assembly.GetExecutingAssembly(),
        Swagger = new CommonServices.SwaggerSettings{
          Version = "v1",
          Title = "Service_Name",
          Description = "API REST do Módulo de " + ("Service_Name").ToUpper()
            + " da solução SG Web."
        }
      });
    }

    public void Configure(IApplicationBuilder app)
    {
      app.UserCommonsMiddlewares(new CommonMiddlewares
      {
        Env = _environment,
        PathBase = EnvVariables.LINEAR_API_SERVICE_NAME_BASE_PATH,
        Swagger = new CommonMiddlewares.SwaggerSettings
        {
          Version = "v1",
          Title = "Service_Name"
        }
      });
    }
  }
}

Context.cs:

using Linear.Infrastructure.Data.Audit;
using Linear.Infrastructure.Data.MultiTenancy;
using Microsoft.EntityFrameworkCore;

namespace Linear.Service_Name.DataBase.Entities
{
  public class Context : DbContext
  {
    public virtual DbSet<Sample_NamesEntity> Sample_Names { get; set; }
    private readonly IAuditEntity _auditEntity;
    private readonly IMultiTenancy _multiTenancy;
    public Context(DbContextOptions<Context> options, IAuditEntity auditEntity,
      IMultiTenancy multiTenancy)
      : base(options)
    {
      _auditEntity = auditEntity;
      _multiTenancy = multiTenancy;
    }
    #region Métodos Protegidos
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
      => modelBuilder.ApplyConfigurationsFromAssembly(typeof(Context).Assembly);

    #endregion
    #region Métodos Públicos
    public override int SaveChanges()
    {
      _multiTenancy.OnSaveChanges(this);
      _auditEntity.OnSaveChanges(this);
      return base.SaveChanges();
    }
    public int SaveChangesWithoutMultiTenancy()
    {
      _auditEntity.OnSaveChanges(this);
      return base.SaveChanges();
    }
    public int SaveChangesWithoutMultiTenancyAndAudit() => base.SaveChanges();
    #endregion
  }
}

Project link to download: https://drive.google.com/file/d/1YWlm_teyGMjJe193AwrFqe3VAeVVKWLq/view?usp=sharing

I've been stuck with this problem for over 3 hours, tried a lot of suggestions on internet and still no sucess, i appreciate if i have some help.

Upvotes: 4

Views: 9285

Answers (1)

dglozano
dglozano

Reputation: 6607

After doing some research, it seems that there is a problem with projects with docker integration and the EF Core tooling.

I have downloaded your code and this is the content of your Directory.Build.props

<Project>
  <PropertyGroup>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/obj/**/*</DefaultItemExcludes>
    <DefaultItemExcludes>$(DefaultItemExcludes);$(MSBuildProjectDirectory)/bin/**/*</DefaultItemExcludes>
  </PropertyGroup>

  <PropertyGroup Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' == 'true'">
    <BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/container/</BaseIntermediateOutputPath>
    <BaseOutputPath>$(MSBuildProjectDirectory)/bin/container/</BaseOutputPath>
  </PropertyGroup>

  <PropertyGroup Condition="'$(DOTNET_RUNNING_IN_CONTAINER)' != 'true'">
    <BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/obj/local/</BaseIntermediateOutputPath>
    <BaseOutputPath>$(MSBuildProjectDirectory)/bin/local/</BaseOutputPath>
  </PropertyGroup>

</Project>

According to @bricelam in this issue the root of the problem lies here:

Changing BaseIntermediateOutputPath from its default when not running inside a container breaks the EF Core tooling experience (*)

Since your BaseIntermediateOutputPath was changed from its default to obj/local when running outside the docker container, what you need to do is let the EF Core CLI know where to find that folder. You can accomplish that by using the --msbuildprojectextensionspath parameter. In your case, it would like like this (as suggested here):

dotnet ef migrations add NewMigration --msbuildprojectextensionspath obj/local

If you are still unable to make it work, you could follow the discussion in this other issue. In there, it was suggested that another possible fix is to change a bit your Directory.Build.props and *.csproj files so that the latter looks like the following:

<Project> <!-- Note: No Sdk="" here. -->

  <PropertyGroup>
     <!-- Don't use $(Configuration) since it isn't set yet. -->
    <MSBuildProjectExtensionsPath>$(MSBuildProjectDirectory)\_intermediate_\</MSBuildProjectExtensionsPath>
  </PropertyGroup>

  <!-- MSBuildProjectExtensionsPath must be set before this gets imported. Directory.Build.props is too late. -->
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

  <!-- (Project content goes here) -->

  <Import Project="Sdk.targets" Sdk="Microsoft.NET.Sdk" />

</Project>

Upvotes: 7

Related Questions