Why will the .NET Core CLI ("dotnet") generate a "dll" file aside from an "exe" file? - .net-core

I'm trying the "dotnet" command line tool. For example, I can run:
dotnet new console
This creates a new project, and then
dotnet build
It will generate bin/Debug/netcoreapp3.1/XXX.exe and bin/Debug/netcoreapp3.1/XXX.dll.
Why will it generate a DLL file? Is it usable in other cases?

When you use the command
dotnet new console
the generated project file looks like
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
</Project>
Line
<OutputType>Exe</OutputType>
specifies that .exe would be generated. This executable simply runs your application which is stored inside the DLL file (the DLL file may be executed directly via dotnet full_generated_dll_path). I guess .exe output is convenient in services / daemon scenarios.
The project usually has some dependencies (both managed and unmanaged), so the output contains a lot of DLL files. Looks like there is no reason to merge EXE file and DLL file, because you still have many other DLL files (and application logic should probably also be separated from the way to execute the application).
From the distribution point of view single file which contains all you need to execute the application seems convenient so this feature was added to to .NET Core 3.

Related

Azure DevOps: publish self-contained .net Core app with Chocolatey

I need to create a self-contained .net core (3.1 in my case) app and to pack & publish using chocolatey so it can be installed and used.
I'm using Azure DevOps and have a feed on my own where I'm supposed to publish the chocolatey package.
The objective is to do this in the build pipeline, so, among other tasks I have:
dotnet publish task: creates the self-contained executable
chocolatey pack task: creates the .nupkg from a very simplistic .nuspec (only mandatory fields) I created.
My current problem is that the .nupkg file created contains always the project files and not the executable generated.
To try and work around it I even made the chocolatey pack's task work directory the same as the dotnet publish's task output one.
What am I missing? Is there another approach?
Azure DevOps: publish self-contained .net Core app with Chocolatey
It depends on whether you include the contained executable file in your .nuspec file.
If we include the contained executable file in the .nuspec file, chocolatey will create the .nupkg include the contained executable file, like:
<files>
<file src="IngestCanonicLtesConsole\ContainedExecutable.exe" target="Tools\ContainedExecutable.exe" />
</files>
We could add this contained executable file in the package:
So, if we are only include the mandatory fields without the <files>contained executable </files>, it will not include the contained executable file.
Besides, we need to include the contained executable file in the .nuspec file, we could change the output of the dotnet build to $(System.DefaultWorkingDirectory)\IngestCanonicLtesConsole, so that we could use the relative path in the .nuspec file.
Please check the document .nuspec reference for some more details.
After a few tests I realized that the chocolatey pack will "pack" all files that in exist in the same folder as the ".nuspec". Not sure this is because I don't set anything on tool.
Basically, my solution was to copy my ".nuspec" file to the folder where my executable was.

Can .Net Core 3 self-contained single executable be decompiled?

I tried using Dotpeek and ILSpy.Net to decompile (my own code), they failed.
Do I need special obfuscation on distributed binaries of .Net Core 3 self-contained single executable ?
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishTrimmed>true</PublishTrimmed>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
</Project>
The single-file exe is really an unmanaged wrapper and ILSpy doesn't support decompiling this. But when you run the exe, it unwraps its contents to a temp folder. So you can find the managed dll there and decompile it using ILSpy.
To find the temp folder, you can use any tool that shows locations of assemblies loaded by a process. SysInternals Process Monitor (procmon) is a good one.
You can setup procmon to filter by your exe name, and when you launch your exe, procmon should show some events for assemblies being loaded from a temp folder:
You can browse to that folder and find your managed dll there. And you can decompile using ILSpy from that location.
I wrote a blog entry: https://eersonmez.blogspot.com/2020/02/ilspy-decompiling-net-core-self.html
I wrote a small dotnet tool after I stumbled upon this question and couldn't find a lightweight tool myself other than ILSpy.
You can install it using the following dotnet command: dotnet tool install -g sfextract.
After installing it, run it using the following command: sfextract application.exe -o output-dir
The bundle format for .NET 5.0 (bundle version 2) is identical to previous versions. .NET 6.0 (bundle version 6) has an additional field for each file entry containing the compressed size, since single-file applications can now be compressed using gzip by setting EnableCompressionInSingleFile to true.
https://www.nuget.org/packages/sfextract/
https://github.com/Droppers/SingleFileExtractor
Update 07/2022: .Net 5 single-file does not automatically unpack to the same temporary location as before. to force it to be unpacked you would need to add the following:
in the project file add these properties (according to theseMicrosoft docs):
<PublishSingleFile>true</PublishSingleFile>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
Add an environment variable DOTNET_BUNDLE_EXTRACT_BASE_DIR with the location you want the files extracted to.
Update: One of the announcements made regarding .Net 5 states that the way single-file executables will be made would change, so this method will not work for them.
I wanted to add on #Eren Ersönmez's answer, that while ILSpy DotPeek don't support this at the time, since the self-contained single file is just a wrapper that contains all your DLLs and gets extracted on runtime, simply knowing where it is extracted to can save you using ProcMon or ProExp or windbg.
If you use windows you can go to c:\Users\{Local Username}\AppData\local\temp\.net\{Name of executable}
which should lead to somewhere similar to
c:\Users\alenros\AppData\Local\Temp.net\MyTestApplication
Launch your exe, and a folder with the same name will be created in that location.
The folder will contain randomly named folders. open the latest one and there you will find all your extracted DLLs, which can then be decompiled.

How to configure build for build undependent projects

I have a web project (asp.net) and I have several modules which should building in folder of the main project.
I can't find information about it.
I would like just build the main project and all modules should build too, but they not dependent with the main project.
Well, there still would be some dependency involved. You can use MsBuild task to build your projects along with main project. There are several options on how to include msbuild script to your solution, here is one of possible ways that allows to change the list of modules without reloading the MainProject and without adding dependencies to it.
Let's say we have MainProject and 2 modules: ClassLibrary1 and ClassLibrary2. Create a BuildModules.csproj file like this:
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="BuildModules" ToolsVersion="4.0">
<ItemGroup>
<ModuleProject Include="ClassLibrary1\ClassLibrary1.csproj"></ModuleProject>
<ModuleProject Include="ClassLibrary3\ClassLibrary3.csproj"></ModuleProject>
</ItemGroup>
<Target Name="BuildModules">
<MSBuild Projects="#(ModuleProject)" Properties="OutputPath=..\MainProject\Bin\Debug;Configuration=Debug;" ContinueOnError="true">
</MSBuild>
</Target>
</Project>
Now this is a concept only, so I've hardcoded the path to bin\debug folder. ContinueOnError is true so in case some error occurs, it doesn't affect on MainProject build process. Put this file in your solution root folder.
Now in MainProject properties on Build Events tab add the following Pre-build command:
call C:\Windows\Microsoft.NET\Framework64\v4.0.30319\msbuild.exe $(SolutionDir)BuildModules.csproj
The path to msbuild.exe may vary.
Now each time you build, it would rebuild your assemblies and you can easily change the list of modules in your BuildModules.csproj file.
UPDATE 1:
TFS not deploying all files. I guess this is because of our hardcoded paths to msbuild and etc. Try moving Pre-build command to MainProject.csproj file, in BeforeBuild target:
<Target Name="BeforeBuild">
<MSBuild Projects="..\BuildModules.csproj" Properties="Configuration=Debug"/>
</Target>
I'm not sure about the path though, but should be like this. And remove Pre-build command from build.

How do you include build outputs as additional files using web deploy (MSDEPLOY)?

I have a web project that has a post-build event that produces some minified files. Assume for the moment that this needs to remain a post- build event, and cannot be changed into a pre-build event.
I have successfully used a .wpp.targets file to package additional files:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
<PropertyGroup>
<SourceRoot>$(BuildDirectory)\Sources\Web</SourceRoot>
</PropertyGroup>
<ItemGroup>
<FilesForPackagingFromProject Include="$(SourceRoot)\ExtraScripts\Normal.js">
<DestinationRelativePath>Scripts\%(RecursiveDir)%(FileName)%(Extension)</DestinationRelativePath>
<FromTarget>Web.wpp.targets</FromTarget>
</FilesForPackagingFromProject>
</ItemGroup>
</Project>
Unfortunately, this fails when I do the same thing for the files produced by the post-build step. This is because the CopyAllFilesToSingleFolderForMsdeploy target executes before the build. Even before the PrepareForBuild target.
Is there a way to add extra files and folders to the deploy package when they are produced during the build?
There was a similar question before (Add Plugin DLL in MVC 4 Website after publish).
You can deploy files only if they have been a part of your project before.
What we usually do is that we include those files as dummy files in our project and overwrite them during the build process. Because those files are part of your project, this approach will publish those files.

Specifying folders not to sync in Web Deploy

I use the following script to deploy my ASP.NET MVC app to our web server:
C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe MySolution.sln^
/p:Configuration=TeamCity-Test^
/p:OutputPath=bin^
/p:DeployOnBuild=True^
/p:DeployTarget=MSDeployPublish^
/p:MsDeployServiceUrl=https://mywebserver.com:8172/msdeploy.axd^
/p:username=MyDomain\MyUser^
/p:password=MyPassword^
/p:AllowUntrustedCertificate=True^
/p:DeployIisAppPath=mywebsitename.com^
/p:MSDeployPublishMethod=WMSVC
Now I need to specify to not sync the /uploads folder. Can I specify that in this script? Thanks!
Clarification:
I have the Uploads folder in my project. I'd like for Web Deploy to create the folder. I do not want it to delete the folder/subfolders/files from my web server because it contains user-uploaded content.
Clarification #2:
I just found the SkipExtraFilesOnServer=True option. However, I don't want this to be global. I'd like to set it to a single folder.
UPDATE:
Apparently, what you really want is prevent web deploy from removing existing directory on the destination server, but still have the folder created in case it's not there. You can accomplish this as follows:
create YourWebProjectName.wpp.targets file next to you the project file with the following content:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<MsDeploySkipRules Include="SkipELMAHFolderFiles">
<SkipAction></SkipAction>
<ObjectName>filePath</ObjectName>
<AbsolutePath>$(_DestinationContentPath)\\NameOfYourFolder\\.*</AbsolutePath>
<Apply>Destination</Apply>
<XPath></XPath>
</MsDeploySkipRules>
<MsDeploySkipRules Include="SkipELMAHFolderChildFolders">
<SkipAction></SkipAction>
<ObjectName>dirPath</ObjectName>
<AbsolutePath>$(_DestinationContentPath)\\NameOfYourFolder\\.*\\*</AbsolutePath>
<Apply>Destination</Apply>
<XPath></XPath>
</MsDeploySkipRules>
</ItemGroup>
</Project>
Change NameOfYourFolder and YourWebProjectName accordingly. This assumes, you have it in the root, I believe, you can use relative path if it's not the case.
The first MsDeploySkipRules entry tells webdeploy not to remove any files in Name_OfYourFolder.
The second MsDeploySkipRules tells webdeploy not to remove any child folders in Name_OfYourFolder.
Also, to have the folder created if it's not present on the destination server, you have to do the following:
include the folder into the project
add a dummy DeployemntPlaceholder.txt file into it and include it into the project as well
DeployemntPlaceholder.txt is required to tell MSBUild to add the folder into the package: empty folders are ignored.
I've tested this approach and it works fine when you run publish in the manner you've shown. I've used this answer to get the msbuild items syntaxt right. I believe, this is a MSBuild way to customize flags, passed to webdeploy by MSBuild Deployment Pipeline.
If you ran MSDeploy directly, you could use skip arguments in the following manner:
-skip:objectname='filePath',absolutepath='logs\\.*\\someNameToExclude\.txt'
UPDATE 2
You might also want to have ACL write permissions set on your \Uploads folder - there's a complete guide to do this: Setting Folder Permissions On Web Publish
Conserning the original question "Specifying folders not to sync in Web Deploy", the easiest way to do this is as follows:
You can create a publish profile and add the following lines:
<PropertyGroup>
<ExcludeFilesFromDeployment>
File1.aspx;File2.aspx
</ExcludeFilesFromDeployment>
<ExcludeFoldersFromDeployment>
Folder1;Folder2
</ExcludeFoldersFromDeployment>
</PropertyGroup>
I've tested this approach for excluding files using publish profiles. An easy guide is here (scroll to Edit the .pubxml file to exclude robots.txt section).
You can also do this in .wpp.targets file or edit you csproj. See more information at Web Deployment FAQ for Visual Studio and ASP.NET

Resources