.net core 2.0 console app : exe file location - .net-core

I am working with .net core 2.0 console application. I need to run this console app using command prompt.
Like,
MyApp.exe arguments
I published the console app using below command to generate .exe :
dotnet publish -c Release -r win10-x64
It creates multiple .exe file,
1) \bin\Release\netcoreapp2.0\win10-x64
2) \bin\Release\netcoreapp2.0\win10-x64\publish
I believe both are same and I can use (2) as published version of the app. Correct me if wrong.
I am not sure why it generates .exe at (1) and does not contain bunch of dlls at there.
What is the difference?
anyone can give me more information about this?

The first one is still a framework-dependent deployment, it used when you call dotnet run -r win-x64. It resolves and configures the shared framework via the information in .runtimeconfig.json and your PATH environment variable and locates the DLLs via a values in the .runtimeconfig.dev.json and .deps.json based on your global packages cache (=> specific to your machine and user).
For deploying self-contained applications, the publish folder contains all the necessary assets. The host uses the local dlls instead of the shared framework and as well as the necessary DLLs.

Related

How do I integrate exe publishing with the VS2019 build of the console .net core 2.2 application?

I saw a couple of similar questions but so far I found no single answer to the problem of integrating the publishing step with my build process. Unfortunately the dotnet publish command rebuilds the project again meaning that if I put the "dotnet publish" command in the project's Post-Build steps I get an infinite loop of building retries.
What I want to achieve is to get an exe built for my .NET Core 2.2 Console App for a few selected environments eg. osx and windows-10, possibly linux too, each in its own folder. Obvious condition is that it has to be integrated with the build, so no extra manuals steps (commands) are required. This has to work from within VS2019 Pro as well in CI (like AzureDevOps).
Is this basic step achievable or .Net core was a major step-back in the progress of software development?
I hope I just miss something and I am just grossly exaggerating. :)
Thanks, Radek
How do I integrate exe publishing with the VS2019 build of the console
.net core 2.2 application?
Actually, I think you do not need to worry about this.
dotnet publish already contains the build process. Publish process will first execute Build and then run publish. In a word, Build is a part of Publish process.
So when you input dotnet publish under Build, you will get an infinite loop of building retries.
Solution
----- Just delete post-build event in xxx.csproj file and just dotnet publish directly and it will run the build process first.
You can test in the local VS and when you right-click on your project-->Publish, it will show the step in the output windwow.
In addition, as far as I know, Azure DevOps has a task called dotnet publish which contains Build.
And if you want to do some msbuild custom target only for publish step, you can add a condition like Condition="'$(DeployOnBuild)'=='true'", it will execute for Publish process rather than the normal build step(right-click on your project-->Build).
<Target Name="testone" Condition="'$(DeployOnBuild)'=='true'" AfterTargets="Build">
xxxxxxxxxxxxxx
</Target>
---------------Update 1----------------
First question
Actually, the build of the publish is the pure process and then publish will copy the content of the build output into publish folder. So the execute program is just from the build output folder.
See the publish log:
So you should not specify a publish target under the build process. This is superfluous.
Second question
To generate this program for Window-10, linux or osx, you can try these command line to publish your project:(Release is the standard release build configuration)
For Win-10:
dotnet publish -r win10-x64 -c Release --self-contained
Linux:
dotnet publish -r linux-x64 -c Release --self-contained
For osx:
dotnet publish -r osx.10.12-x64 -c Release --self-contained
In this way, the project is first built according to the specified runtime and then published.
More info about .NET Core RID Catalog, you can refer to this document.
Update 2
I think you should change the configuration in this package UI:
Then click Save.
Also, when you publish this web project, please try to delete bin and obj folder and then publish it.
Debug: bin\Debug\netcoreapp2.1\publish
Release: bin\Release\netcoreapp2.1\publish
Or you should use dotnet command as I described to publish the project. The path is under Debug or Release folder.
What I want to achieve is to get an exe built for my .NET Core 2.2
Console App for a few selected environments eg. osx and windows-10,
possibly linux too, each in its own folder. Obvious condition is that
it has to be integrated with the build, so no extra manuals steps
(commands) are required. This has to work from within VS2019 Pro as
well in CI (like AzureDevOps).
Is this basic step achievable or .Net core was a major step-back in
the progress of software development?
It's a good idea but as I know what you want is not 100% supported for now.
It seems that your expected scenario is:
Click the Build(F5) button=>Project will be built in different platforms win-x64,win-x86,linux-x64...,also will be published in different platforms automatically with self-contained mode.
But the fact is:
1.Click the Build button(Build(F5) equals to the Build button in project context) will run the Build Target (A default built-in target for each project for build). => dotnet build in command-line.
2.Click the Publish button will run the Publish Target (A default built-in target for each project for publish). => dotnet publish in command-line.
3.If you have any build/publish command in post-build event, it will result in an expected loop. So it's hard to combine publish with build perfectly since they're two actions in VS with different button/behavior/corresponding command. (Only dotnet publish command can recognize --self-contained)
4.To build/publish the projects in parallel, the batch file or msbuild targets file is a good choice.
#1.Build different platforms using one build command see this. #2.Publish different platforms using one command see this. (They both use custom .targets to do the job)
Suggestions:
According to your scenario, I think you can consider using #2. It's not necessary for you to build with different platforms during your normal development.
1.In local VS when you're developing and debugging:
The default build button/option is enough for you to debug.
2.In local VS when you want to publish the project in different platforms:
Use #2 above so that you can publish them using cmd.exe or PS.exe. (Via command dotnet msbuild -restore -t:PublishAllRids)
3.When you're automating the CI pipeline in AzDeops(Also use #2):
A CMD/PS task with dotnet msbuild -restore -t:PublishAllRids command is enough. Dotnet publish will build automatically if we don't pass --no-build argument.
4.Azure Devops Service suggests separate the jobs in different tasks, it's not recommend to Integrate Publish with Build heavily, especially for .net core projects. (Here's official sample about CI for .net core projects.)

Why when compiling .NET Core console application we end up with both dll and exe files?

I have noticed that both dll and exe files with the name of the project are created on Windows when compiling a .NET Core console application. Why is that? In full .Net framework only the exe file would be created.
Prior to .Net Core 3.0, only the dll was created (although you could still do a single file build that was platform-dependent). In these cases you had to use the command dotnet MyProject.dll to start your program.
With .Net Core 3.0, they added the exe, which is still really just a wrapper around the command above. On other operating systems it also creates an executable file, it just names it MyProject instead of MyProject.exe
If people have old scripts that still make the dotnet command, this setup doesn't break them, but if you want to just use an exe, you can do that too.

.Net Core 3.0 NuGet DLLs

Let's say that we include Nuget Package Microsoft.Extensions.Configuration in a Console .Net Core app, and include the same package in another Console .Net Core app.
When we publish these two apps, each app would publish:
Microsoft.Extensions.Configuration.Abstractions.dll
Microsoft.Extensions.Configuration.dll
in each folder.
If we had 10 console apps using the same package, we would have these dlls in 10 different folders in the application server. If we reference to multiple NuGet packages, the number of dependency dll files would multiply.
Is there a way to consolidate these dlls in one folder in the app server, so when we publish our executable, all we need to do is move the executable and configuration file to the server, and it will find these dlls in a common folder. Sort of setting a dll Path.
In consideration of Trisped's suggestion, I am posting an answer that neither me nor my boss are completely satisfied with. But for the time being to the best of my knowledge, the way to consolidate these DLLs is by writing a utility program to move those DLLs to a designated common DLL folder. And, at the same time update both .deps.json file and .runtimeconfig.json file with the new location path of the common DLL folder and additionalProbingPaths folder path structure, respectively.
We can't do this by hand manually because there would be too many DLLs to move and too tedious to edit .deps.json file, which got wiped out everytime we publish the Console App solution. I have written the utility program. Unfortunately this is company's IP so I can't share the code.
The idea is to enumerate the DLLs in the publish folder and store those filenames in a collection / dictionary, and later on use that dictionary to update the runtime dll paths in .deps.json. For CLI use, I use these options:
-c Release -f netcoreapp3.0 --self-contained false -r --runtime win-x64 -o <publisheFolder>
It would be very helpful if Visual Studio Publish Profile would include a folder that we can specify, where all Third Party and Nuget Package DLLs will reside, in addition to the Publish folder, where only the app executable, app dll, configuration files, deps.json and runtimeconfig.json will reside. Even better if the CLI would allow additional option to specify the DLL folder and, not include the runtime folder when --self-contained false is indicated.
After all, isn't one of the main purpose of DLL to allow applications to share code with each other?

Can I shrink a dotnet publish package

I have recently started developing using dotnet core (as opposed to old fashion plain .net) to create a number of small utility console applications.
The development is fine and it has come to the point I want to publish them.
I am using the CLI and as I am only interested in Win 10 deployments, tried
dotnet publish -c release -r win10-x64
It worked and built me a "publish" folder where everything seemed to work, though the "publish" folder is huge (~70mb) compared to the size of the app (~500 lines of code).
As I am only going to deploy to Win10 machines is there a way to package this so I don't need all the .NET files? I thought that was what the -r option was for but that does not seem to have achieved much.
It depends on how you want to deploy your app/who is going to use them.
The -r flag creates a self-contained app. This causes the publish command to include the necessary .NET Core DLL's for the specified platform (and platform specific nuget packages if they are avaiable), which means anyone can use the app without having to install .NET Core runtime.
If you remove the -r flag then publish will only include the DLL's for you app. But this means whoever wants to use your app must first install the .NET Core runtime.
You can see the difference by using the -o flag to write the publish output to different directories e.g.
dotnet publish -c release -r win10-x64 -o ./publish-win10
or
dotnet publish -c release -o ./publish-any
Now go and have a look at what has been written to ./publish-win10 and ./publish-any folders and you can the difference.
If you are installing them onto a system where the .NET Core runtime is already present then you can just distribute the DLL and save a lot of space. However if you want to be able to distribute the app without the end user having to worry about having the .NET Core runtime installed then the -r flag to create a self-contained distribution is the way to go, but results in the 'package' including the necessary .NET Core assemblies.
AFAIK the -r flag does not affect how you app is compiled, just what runtime DLL's are included as part of the publish command. So you always get the same DLL for your code if you publish it for win10-x64 or with, or without, the -r flag so your app DLL will run on any (.NET Core compatible) platform, but I am happy to be corrected on that point.
Unlike .NET 4.x which you are used to where building is the standard to create an output, .NET Core (And .NET 5) considers building and publishing to be very different.
The huge (70MB) size is because the publisher is assuming that your target does not have any form of the .NET Framework installed, so is bundling it in with your project.
You can change your publish line to
dotnet publish -r win-x64 --self-contained false
Just by itself, this will create the .NET Core standard - A .dll (Your application), a .exe (That runs the application), some .json files for settings, and a .pdb file for debugging symbols.
To alter the application to the .NET Framework standard output that you are used to, open the .csproj file in a text editor, and below the
<TargetFramework>netx.x</TargetFramework>
line, add
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
And rerun the publish command. This will result in a single .exe and a single .pdb in the publish directory (The .pdb file which you can safely delete).
Note: Since you have included --self-contained false, the target will need the specified version of the .NET Framework (The one specified in your .csproj file) installed. Whilst many versions of the .NET Framework are currently installed on most Windows 10 Devices (Generally located at C:\Windows\Microsoft.NET\Framework or C:\Program Files\dotnet\), the .NET Core / .NET 5 Runtimes aren't yet as common (Although will likely be distributed through Windows Update in the near future), so may require a once-off download if the recipient of your .exe does not have it.
Whilst the .NET Core / .NET 5 resultant binaries ARE larger (Although by around 150kb - Not 50MB), they run significantly faster than their .NET Framework 4.x counterparts.

Same MSBuild file, different results on local machine and CCNet

Background
I am utilizing the following:
VS 2012
.NET 4.5 apps including an MVC4 app, a C# Domain app, and NUnit projects.
A custom MSBuild File
CruiseControl.NET running on a build server
I have the following build targets:
Clean: deletes the buildartifacts directory
Init: creates a blank buildartifacts directory
Compile: compiles the solution
Test: runs NUnit Tests
Package: creates a ZIP package for deployment
Deploy: Deploys package to a remote IIS Server
Problem
When I run the build from my local machine, it packages and deploys perfectly.
When CCNet runs the same build target, the files appear to be deployed
Attempted Resolutions / Potential Leads
I have run the same target in PowerShell from both machines and have seen no errors or warnings on either.
Because I tell CCNEt to override the framework to point it to the .NET 4.5 files I've copied to the build server, I made my local machine point to the same files when running MSBuild but my local build still worked and deployed.
In Visual Studio, I have ensured that all content files are marked with a Build Action of "Content" and a Copy to Output setting of "Copy Always".
The Code
Available in a gist at https://gist.github.com/53ef2a63931d190593f6
(file has been scrubbed, app name & credentials replaced, etc.)
It turns out, this was a completely unrelated issue.
After doing a diff of both build logs, I noticed that the build server working copy contained old files that no longer existed. This led me to discover that the issue ended up being that the repository wasn't being updated.
CCNet was receiving a subversion error that wasn't registering as an error
As a result, I was never getting the latest version of the repository, and so all files were broken.
The error is related to this StackOverflow question, regarding a sqlite error when attempt to use tortoisesvn to update. The solution in my case was to simply delete the build server's working copy, recreate the folder, and perform an svn checkout.

Resources