--output is relative to the current working directory instead of the .csproj file. This does not seem to be documented here or under What's New
⚠Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
Thank you for reporting this. I've confirmed the behavior.
Assigning to @mairaw as part of the CLI updates.
if output folder is specified for a solution all the outputs get dumped into that single folder. Previously, it would do each project into separate folder.
@gzinger I was kind of wondering about that... Haven't tested that, we mostly build the .csprojs directly...
~@gzinger Please file a bug on the CLI code repo: https://github.com/dotnet/cli~
Not a bug but a breaking change.
I have always wondered, what is the motivation for the --output flag being relative to the .csproj instead of the current working directory? It has always been a "gotcha" for me since no other CLI I've used treats paths that way.
I have the same issue here. We had some .bat files that publish projects and now they are all failing. Please fix this
Same here, we have to fix a lot of scripts and Dockerfiles because of this change. Will this be fixed to behave like in 2.1 or should I start to change my files?
This was an intentional breaking change for 3.0 since previously people reported that re-rooting arguments to command line arguments is unnatural and no other tool ever does that.
Fun fact: This is the original behaviour of the CLI for project.json. The re-rooting happened with the move to MSBuild (1.0) and so people complained about it but I was too late to make the change for 2.0 so it now got into 3.0 with https://github.com/dotnet/cli/pull/9892
If this is an intentional breaking change, do we have a way to force a dotnet publish using the previous version? I had to uninstall net core 3 on my system to avoid issues but I would like to have it for future projects.
You can use a global.json file to pin the SDK version you want to build with to do that.
@mairaw I elevated this to P0 and I added it to the oct milestone. I think this needs to be documented asap as it is a huge difference from 2.0 to 3.0.
Feel free to readjust.
Due to this change, I'm unable to build my docker image:
Dockerfile:
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-alpine as build
WORKDIR /app
COPY helloworldapi/*.csproj .
RUN dotnet restore -r linux-musl-x64
COPY . .
RUN dotnet publish -c Release -r linux-musl-x64 -o out --no-restore
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine as runtime
WORKDIR /app
EXPOSE 80
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet","./helloworldapi.dll"]
Error:
/usr/share/dotnet/sdk/3.0.100/Microsoft.Common.CurrentVersion.targets(4563,5): error MSB3024: Could not copy the file "/app/obj/Release/netcoreapp3.0/linux-musl-x64/helloworldapi" to the destination file "bin/Release/netcoreapp3.0/linux-musl-x64/helloworldapi", because the destination is a folder instead of a file. To copy the source file into a folder, consider using the DestinationFolder parameter instead of DestinationFiles. [/app/helloworldapi.csproj]
The command '/bin/sh -c dotnet publish -c Release -r linux-musl-x64 -o test --no-restore' returned a non-zero code: 1
This was working in 2.2 but in 3.0 it fails.
Is there any workaround?
Looks like you are copying the csproj file from the subdirectory to the parent directory. the project file then includes the rest of the helloworldapi folder during build which collides with the name of the executable being generated. The error will also occur without any -o parameter added. See https://github.com/dotnet/cli/issues/7782 for example.
I'd suggest not modifying the folder hierarchy when copying:
FROM mcr.microsoft.com/dotnet/core/sdk:3.0-alpine as build
WORKDIR /app
COPY helloworldapi/*.csproj helloworldapi/
RUN dotnet restore helloworldapi -r linux-musl-x64
COPY . .
RUN dotnet publish helloworldapi -c Release -r linux-musl-x64 -o out --no-restore
FROM mcr.microsoft.com/dotnet/core/aspnet:3.0-alpine as runtime
WORKDIR /app
EXPOSE 80
COPY --from=build /app/out ./
ENTRYPOINT ["dotnet","./helloworldapi.dll"]
I see the motivation for doing this, although I wouldn't have described the previous behavior as confusing.
I do not agree with how this has been implemented, especially if the publish has been run on a solution file rather than a csproj.
Currently if we run this on a solution file everything gets dumped into a single output directory, which to me is not desired behavior.
Are there any plans to support a per project output directory when building solution files?
This could be achieved with an optional param or similar.
**Update - If I run publish on a solution without specifying an output directory, then the output is per project.
ProjectDirectory/bin/Release/netcoreX.X/publish for example.
The inconsistent behavior there is confusing
My wish is that running publish on a solution should return an error. there are multiple issues that make it hard to get a consistently working output for publish in a solution, especially if there are library projects in there as well. I recommend only calling publish on specific projects you actually want to publish to avoid issues.
I have the same problem and it causes issues to me when building my solution with Azure DevOps.
I have a solution with a lot of projects. Each project is a dedicated app for a docker container. Previously (2.2.105), when executed the command:
dotnet publish project.sln -c Release -o out
the output was related to the project, so in the per project Dockerfile it was easy to reference to the out folder.
Now, with dotnet core 3.0, executing the same command all project generates the output into the very same folder located in the solution folder, which is a mess.
d:\Git\ViBE\ViBE>dotnet --version
2.2.105
d:\Git\ViBE\ViBE>dotnet publish ViBE.sln -c Release -o out
...
(log shortened)
....
ViBE.Device.GPIO -> d:\Git\ViBE\ViBE\ViBE.Device.GPIO\out\
ViBE.Device.HardwarePanel.TestHarness -> d:\Git\ViBE\ViBE\ViBE.Device.HardwarePanel.TestHarness\out\
....
d:\Git\ViBE\ViBE>dotnet --version
3.0.100
d:\Git\ViBE\ViBE>dotnet publish ViBE.sln -c Release -o out
...
(log shortened)
....
ViBE.Device.GPIO -> d:\Dropbox\Git\ViBE\ViBE\out\
ViBE.Device.HardwarePanel.TestHarness -> d:\Git\ViBE\ViBE\out\
....
I understand that was an intentional change in 3.0, but I really disagree with that.
How can I achieve the same result with dotnet core 3.0?
Is there any way?
This change breaks compatibility with current solutions of continuous integration unnecessarily. I also disagree and this brings no feature or benefits or simplification for end-users.
this brings no feature or benefits or simplification for end-users.
I disagree with this claim. @dasMulli previously commented:
This was an intentional breaking change for 3.0 since previously people reported that re-rooting arguments to command line arguments is unnatural and no other tool ever does that.
Which I do agree with. According to their comment, this change was done entirely for simplification (and consistency) with other tools, tools which end-users are already using.
@staticdev sorry for causing that trouble. It is always unfortunate when things break. It first broke people with the release of VS 2017 and 1.0 Tooling - everyone using the 1.0.0-preview2* CLIs was then broken with the relative path handling and the WTFs on that behaviour didn't stop. Also constantly needning to explain that the path was relative to projects threw of people off - at least the ones I talked to.
You can still use the old behaviour by the way - by passing in the variable directly as MSBuild property:
dotnet build -p:OutputPath=relative/path
dotnet publish -p:PublishDir=relative/path
dotnet pack -p:PackageOutputPath=relative/path
I just ran into this same problem! This is a horrible design decision as now its really hard to package up particular projects in a solution in a CI/CD pipeline on the build server....
@dasMulli I will try that workaround. Would you happen to know if that a permanent solution or will it also cease to function in a later version as well?
@dasMulli recommendation worked for me using both v3.x and v2.x! Thanks! :)
I just hope this is a stable workaround vs. something that may also stop working in a few months.
I don't think this is likely to change as it would have large implications across the stack. The thing that changed was the translation between the arguments to the dotnet CLI and what is passed to MSBuild a layer below (which is what the -p: arguments do directly).
Disclaimer: I don't work for MS and i can't promise anything.
(Nearly) Every CLI argument can be translated to MSBuild arguments, though you might have to look them up in source code like:
https://github.com/dotnet/cli/blob/edb240070dbac6ca80122d06dad51bf9221df62f/src/dotnet/commands/dotnet-publish/PublishCommandParser.cs#L22-L27
Back to the actual topic: The documentation still does not seem to mention .NET Core 3.0 at all, even after it has been released.
We're still going through the CLI updates for 3.0.
Removing the milestone for now. I'll add this update when I'm making the updates for this page for 3.0.
@KathleenDollard should we also have an entry at https://docs.microsoft.com/en-us/dotnet/core/compatibility/breaking-changes for CLI breaking changes? We mostly focus on API compat. Or would things like this be part of the migration work I'm doing for for #14471?
Changing from dotnet publish -c Release -o out to dotnet publish -c Release -p:PublishDir=out worked for me.
This change also broke our CI tools.
Can confirm that the -p:PublishDir=./whatever/dir option works as expected.
You may want to consider adding some kind of warning/notice about this change when the -o option is used, it'll probably save people a lot of time and confusion!
This was very confusing! For some applications using a single out directory is fine, but there should be a way to publish separately to filter out tests for example.
-p:PublishDir=out is working, but unless it is documented this could be undocumented and changed in the future.
Same issue with donet pack btw, now all go to single nuget
What is the use case to even use -o from the CLI now ?
@jamescpurcell I just ran into the described issue and don't believe -o makes sense when publishing more than one project, since it would require to be able to re-assemble each published executable's dependencies within the output folder.
Ran into this issue as well but we're using FAKE build system. Use the MSBuild environment workaround. Does it make sense to instead add a new option: -or or --output-relative instead?
so just to clarify, if i want dotnet publish -o <out path> to behave like _any other build CLI tool i have ever used or heard of_ this is the logic i am faced with?
the flag called -o or in literal-flag --output defined from dotnet publish --help as:
-o, --output <OUTPUT_DIR> The output directory to place the published artifacts in.
needs to be replaced with an undocumented flag derived from the source code of the underlying builder.
and that flags name? albert einstein PublishDir
i feel like mugatu right now. am i taking crazy pills or is this absurd to anyone else?
i arrived here after trying to decipher the logic behind having the output directory get nested and duplicated on subsequent publish calls. you cant even use dotnet clean because it cleans everything _except_ the artifact output. and even a `--clean`` flag (arguably should be opt out not in) was denied. its 2020 man why are we having to write a wrapper script around deleting the output artifact before publishing?
please correct me if im way off base here. but its been really confusing to work with these tools. they just seem to consistently do undocumented and unexpected things.
@the-vampiire I haven't seen the output directory get nested and duplicated on subsequent publish calls. Can you share the actual command you're repeating that has this result?
@the-vampiire The reason publish directories get nested is if you publish into the project's directory itself.
The csproj will consider all files and folders next to it as part of the project. Especially web projects will also mark all sorts of files as copy-to-output.
So if you publish again, those files already created on the last run are copied again. To not cause this, publish to a folder outside your project.
here is the command (it occurrs with or without the PSF flag and for any RID)
dotnet publish -c Release -r osx-x64 -p:PublishSingleFile=true -o build
first call
build/
# exe and pdb
# json/config files
second call
build/
# exe and pdb
# json/config files
build/
# json/config files
I'm not seeing that behavior. What SDK version are you using?
@tdykstra
$ dotnet --info
.NET Core SDK (reflecting any global.json):
Version: 3.1.102
Commit: 573d158fea
Runtime Environment:
OS Name: Mac OS X
OS Version: 10.14
OS Platform: Darwin
RID: osx.10.14-x64
Base Path: /usr/local/share/dotnet/sdk/3.1.102/
Host (useful for support):
Version: 3.1.2
Commit: 916b5cba26
.NET Core SDKs installed:
3.1.102 [/usr/local/share/dotnet/sdk]
.NET Core runtimes installed:
Microsoft.AspNetCore.App 3.1.2 [/usr/local/share/dotnet/shared/Microsoft.AspNetCore.App]
Microsoft.NETCore.App 2.1.16 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
Microsoft.NETCore.App 3.1.2 [/usr/local/share/dotnet/shared/Microsoft.NETCore.App]
@the-vampiire that's exactly what i explained above. you will see this behavior when publishing to a directory next to the csproj.
To resolve this issue, publish to a directory outside your project directory.
@tdykstra this happens with most web projects that mark json (and other) files as content for publishing. Once content was published into the directory of the csproj file, it will pick them up again during the next run.
Sdk issue: https://github.com/dotnet/sdk/issues/8786
Alternative is to exclude the directory in the csproj file as metioned in https://github.com/dotnet/sdk/issues/8786#issuecomment-334891814
@dasMulli Thank you for the explanation! Do you have any idea why I'm not able to repro the behavior? Does it depend on a certain setting in .csproj? If I can clearly describe the criteria for making it happen, I can add a warning/explanation in the dotnet publish documentation.
It should repro with:
dotnet new web -o testweb
cd testweb
dotnet publish -o myoutput
dotnet publish -o myoutput
And observe that there will be nested myouptut folders (b/c the build logic thinks the existing myoutput folder is part of your project on subsequent runs).
It should happen for all projects using web SDKs (so Worker, Web - not sure about Razor library SDK)
Thanks, I didn't realize it had to be a web project. I'll reopen this issue and add mention of this behavior to the documentation.
Maybe create a new issue, that's current behavior since 1.0 i think :)
thanks @dasMulli i missed your message from before. that was definitely the issue.
and thanks @tdykstra for adding a warning. i was really confused because this wasnt documented anywhere
Most helpful comment
@staticdev sorry for causing that trouble. It is always unfortunate when things break. It first broke people with the release of VS 2017 and 1.0 Tooling - everyone using the 1.0.0-preview2* CLIs was then broken with the relative path handling and the WTFs on that behaviour didn't stop. Also constantly needning to explain that the path was relative to projects threw of people off - at least the ones I talked to.
You can still use the old behaviour by the way - by passing in the variable directly as MSBuild property: