Efcore: Can't run ef commands using Directory.Build.props with seperate project and startup project

Created on 4 Jun 2018  路  25Comments  路  Source: dotnet/efcore

Upgrading to ASP.Net Core 2.1 added a new recommendation for using Docker as a development environment, which is to add a Directory.Build.props file that will specify where to put the BaseIntermediateOutputPath and BaseOutputPath depending on the executing environment.

With the Directory.Build.props in place everything works as expected except dotnet ef commands. I'm running dotnet ef migrations list -s ./Y/ -p ./X/ The error generated is,

X/X.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.

By following the error's recommendation and adding the --msbuildprojectextensionspath option with the value obj/local, i.e. dotnet ef migrations list -s ./Y/ -p ./X/ --msbuildprojectextensionspath ./X/obj/local, the error reoccurs though now it's requesting that the other project in question's --msbuildprojectextensionspath be given. Error meesage

Y/Y.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.

Running this now with dotnet ef migrations list -s ./Y/ -p ./X/ --msbuildprojectextensionspath ./Y/obj/local everything works as expected.

Directory.Build.props contents are,

<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>

The directory structure of the project is,

/
  Directory.Build.props
  src/
     X/
        X.csproj
     Y/
        Y.csproj

I'm running this in the local environment and all commands were run form the src directory.

This looks similar to #8816, though I'm not sure how to get this work with Directory.Build.props. Can you please assist in providing a solution to this issue?

Further technical details

EF Core version: 2.1.0
Database Provider: Microsoft.EntityFrameworkCore.SqlServer
Operating system: mac OS 10.13
IDE: Visual Studio Code

closed-fixed customer-reported punted-for-2.2 type-bug

Most helpful comment

I meant to say building and debugging works without any issues with my Directory.Build.props file. I am getting below error whether or not I specify the --msbuildprojectextensionspath switch (I tried with both absolute and relative paths to my obj folder):

C:\Users\User1\Source\Repos\Server\DataAccess\DataAccess.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.

$(MSBuildProjectExtensionsPath) is pointing to correct obj folder that I configured $(BaseIntermediateOutputPath) to.

All 25 comments

FYI I have recently been seeing this error when there is a duplicate PK in entity seed data AND there is a watcher on the project (i.e. dotnet watch run). This seems to be unrelated to the causes of the reported issue, but the error is a bit deceiving in this context - so in case anyone else finds there way here because of that, I thought it might be of use.

Same problem here.
Workaround: dotnet ef migrations list --msbuildprojectextensionspath obj/local

Thank you @lukyer, the workaround works!

Is everyone using the same Directory.Build.props file? Where did it come from?

Notes for triage: One way to fix this is for us to hijack the CustomAfterMicrosoftCommonTargets and CustomAfterMicrosoftCommonCrossTargetingTargets properties (like other ASP.NET tools do), but this introduces a new set of problems.

@bricelam I believe the file is created when you create a project on VS with docker integration

I don't see it any of the templates, but I did find it here https://github.com/dotnet/dotnet-docker/tree/master/samples

@richlander Changing BaseIntermediateOutputPath from its default when not running inside a container breaks the EF Core tooling experience. Is this file just part of the sample or did it come from a template? Can we change it?

@divega to follow up.

@richlander Can you direct us to who might know about changing BaseIntermediateOutputPath? This sample is breaking EF Core tooling experiences and we need to decide how to react to this.

@bricelam We followed this guide https://github.com/dotnet/dotnet-docker/blob/master/samples/dotnetapp/dotnet-docker-dev-in-container.md#requirements
Changing BaseIntermediateOutputPath allows the application to be build and run in the docker image while coexisting with "local" files used by the IDE

That's correct @raix. That accurately describes the motivation for the pattern. The workflow works very poorly without this pattern.

If we set these properties to absolute path, it appears to be prepending the project path to it.

The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: Cannot find path 'C:\Users\User1\Source\Repos\Server\C:\Users\User1\.projects\Output\Server\bin\Debug\AnyCPU\netcoreapp2.1\' because it does not exist.

Marking this as blocked until https://github.com/dotnet/dotnet-docker/pull/1033 is merged.

This issue may fixed for docker but I redirect bin and obj folders for a different reason. It is not fixed for me.

@nvmkpk Please file a new issue fully explaining your scenario.

@nvmkpk You're free to change the obj folder; you just need to run dotnet ef with the option --msbuildprojectextensionspath path/to/obj/

@bricelam I tried that too and it did not work. I don't remember what error I ran into of top of my head. I will try that again and file a new issue. Only thing that worked for me was to temporarily disable the folder redirection.

It's a tricky property to override, you need to set it before the SDK targets are imported. You may need to decompose your project files from this...

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

   <!-- ... -->

</Project>

...to this.

<Project>
  <PropertyGroup>
    <!-- NOTE: Must be set before imporing Sdk.props -->
    <BaseIntermediateOutputPath>$(MSBuildProjectDirectory)/myobj/</BaseIntermediateOutputPath>
  </PropertyGroup>
  <Import Project="Sdk.props" Sdk="Microsoft.NET.Sdk" />

   <!-- ... -->

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

I did not have to modify my project file. I set it in Directory.Build.props. This file is imported before any other imports and it just worked for my case.

it just worked for my case

Does that mean using --msbuildprojectextensionspath is working for you? If not, check the value of the $(MSBuildProjectExtensionsPath). It's get set really early in the build pipeline using the value of $(BaseIntermediateOutputPath) which is what requires the weird workaround mentioned above.

I meant to say building and debugging works without any issues with my Directory.Build.props file. I am getting below error whether or not I specify the --msbuildprojectextensionspath switch (I tried with both absolute and relative paths to my obj folder):

C:\Users\User1\Source\Repos\Server\DataAccess\DataAccess.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.

$(MSBuildProjectExtensionsPath) is pointing to correct obj folder that I configured $(BaseIntermediateOutputPath) to.

Can you submit a new issue with a repro attached?

I'm seeing the exact same issue as @nvmkpk . Was this ever addressed? Was a new issue created?

@guitarzan I never got time to create an issue and a repro. Please feel free to create one if you can.

I started creating a repro, but it is working now. I think I was mis-typing either the path to the project or the obj folder.

I would still prefer that dotnet-ef respect the settings in the Directory.Build.props file, but at least there is this workaround.

Was this page helpful?
0 / 5 - 0 ratings