In dotnet 6/7, you can set a flag, IncludeNativeLibrariesForSelfExtract, to include native libraries in the single file bundle. These files are extracted to a directory in the client machine when the single file application is run.
However, I found the flag would also make my extern exe file included in the bundle.
<ItemGroup>
<None Update="extern_tool\clash.exe" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
My program will crash as it can't find the location of clash.exe.
so, How to exclude some exe file when using IncludeNativeLibrariesForSelfExtract?
Related
I am trying to publish my console application into 1 exe file. I have managed to embed the dll files into the exe file by adding to the csproj file:
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<PublishSingleFile>true</PublishSingleFile>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
However I still need my file extractConfig.json in the same space as the exe file as well or else it will not run. How can I embed this file into the exe as well?
It is currently getting published like so:
But I need it so it is just the exe file
There are a few options:
Create the config if it does not exist
When the program starts you check if the config file exist. If not, you create it. You could create this file from a default configuration object that you serialize, or include the configuration file as a string resource or some other way. I would also consider placing this file in the localappdata folder instead, since you might not have write access to the folder of the .exe file.
Exclude the configuration file from the package
You can add the ExcludeFromSingleFile option for the config file so that it is not included in the single .exe file. This will obviously require you to deploy multiple files.
<ItemGroup>
<None Update="extractConfig.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
</ItemGroup>
Spoke with the people I am working with and have gone with the suggestion from #SirOneOfMany and I am now using constants rather than the json file which easily allows me to just have the 1 exe file.
Thanks everyone for the suggestions
I'm trying to obfuscate an .exe file obtained after compiling my .NET 6 project with the "Produce a single file" option, the problem is that no obfuscator works on it, I wanted to know if anyone knows why?
Thanks in advance for your answer
You have to obfuscate main application dll, which is located in the "obj\Release\net6.0-windows\win-x64" folder and copy obfuscated dll to the path.
Here is a working example using Obfuscar. These lines are located in the .csproj file.
<Target Name="Obfuscation" AfterTargets="AfterCompile" Condition="'$(PublishProtocol)'!=''">
<Exec Command=""$(Obfuscar)" obfuscar.xml" />
</Target>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="'$(PublishProtocol)'!=''">
<Exec Command="COPY "C:\Users\Application\obj\Release\net6.0-windows\win-x64\Obfuscated\Application.dll" "C:\Users\Application\obj\Release\net6.0-windows\win-x64\Application.dll"" />
</Target>
After that, when you publish single file exe, your application code inside the archive will be obfuscated.
When you publish a .NET application as a single file, the actual code is located in the DLL file. The EXE file is just a launcher.
Returning to the obfuscation, the idea is to obfuscate the assembly right after it is placed to the intermediate directory by a compiler. E.g. if you use ArmDot you just write:
<Target Name="Protect" AfterTargets="AfterCompile" BeforeTargets="BeforePublish">
<ItemGroup>
<Assemblies Include="$(ProjectDir)$(IntermediateOutputPath)$(TargetFileName)" />
</ItemGroup>
<ArmDot.Engine.MSBuildTasks.ObfuscateTask
Inputs="#(Assemblies)"
ReferencePaths="#(_ResolveAssemblyReferenceResolvedFiles->'%(RootDir)%(Directory)')"
SkipAlreadyObfuscatedAssemblies="true"
/>
</Target>
The same approach can be used with any obfuscator. The key thing is to use the following path: $(ProjectDir)$(IntermediateOutputPath)$(TargetFileName).
After that, the obfuscated assembly (DLL) is published.
When using examples such as
<!--Include in publish-->
<ItemGroup>
<None Include="exampleDirectory\**\*.*" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
</ItemGroup>
This folder has .cshtml and .cshtml.cs files but only the .cshtml.cs files are copied. Is there a specific reason these files do not copy over?
Copy and paste of the required folder into the publish output directory works. Meaning if this copy mechanism just worked and copied all the files this wouldn't be an issue.
I have it setup as <None because I need to have two directories and using <Content gives an error of having two contents being used.
C:\Program Files\dotnet\sdk\3.1.404\Sdks\Microsoft.NET.Sdk\targets\Microsoft.NET.Sdk.DefaultItems.targets(318,5): error NETSDK1022: Duplicate 'Content' items were included. The .NET SDK includes 'Content' i
tems from your project directory by default. You can either remove these items from your project file, or set the 'EnableDefaultContentItems' property to 'false' if you want to explicitly include them in yo
ur project file. For more information, see https://aka.ms/sdkimplicititems. The duplicate items were: 'dirName\fileName.cshtml'; 'dirName\fileName.cshtml' [C:\path\to\projectName.csproj]
Which when set to false for EnableDefaultContentItems it still does not copy the .cshtml files, just the .cshtml.cs files.
why do you have 'None'?
Example:
<ItemGroup> <Content Include="AppData\**" CopyToPublishDirectory="PreserveNewest"/> </ItemGroup>
according to this link
https://blogs.msdn.microsoft.com/kirillosenkov/2015/04/04/how-to-have-a-project-reference-without-referencing-the-actual-binary/
I referenced the assembly of ProjectA in the projectB with ReferenceOutputAssembly=false like below :
<ProjectReference Include="..\ProjectA\ProjectA.csproj">
<Project>{b402782f-de0a-41fa-b364-60612a786fb2}</Project>
<Name>ProjectA</Name>
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<OutputItemType>Content</OutputItemType>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</ProjectReference>
This will indicate a dependency between projects to MSBuild, but won’t pass the output assembly of ProjectA as a reference to the compiler when compiling ProjectB.
MSBuild just copies the assembly A dll into the output directory for assembly B ,not the Satellite Dll.
I need both ProjectA.dll and ProjectA.resources.dll in the output directory but just projectA.dll is copied , Satellite Dll of Project A is not copied..
MSBuild just copies the assembly A dll into the output directory for
assembly B ,not the Satellite Dll. I need both ProjectA.dll and
ProjectA.resources.dll in the output directory but just projectA.dll
is copied , Satellite Dll of Project A is not copied..
The issue also appears in my side and I think when you use the function( Methods in the link) above, it will replicate the dependency without referencing project A, but also ignores the DLLs or resources.dlls referenced by project A. This approach focuses on Project dependencies and ignores other third-party DLLs used by the Project.
This behavior is characteristic of that scenario you used.
However, if you still want to use this function to reference Project A, you can try to use build event or copy task to copy ProjectA.resources.dll into the output path of Project B when you build:
1) Right-click on Project B-->Properties-->Build Events-->Post-Build Event Command line and then input this:
xcopy /y "xxxxxxxxxxx\de\ProjectA.resources.dll" "$(ProjectDir)$(OutputPath)de"
xcopy /y path1 path2: path1 means the path of the original file and path2 means the destination address.
Update 1
generally your solution works but it doesnt work for me because I want
to publish with clickonce and Postbuildevent is not called during the
publish .. I added a before publish tag in csproj of the project B to
run the postbuildevent but it doesnt work
First, you do not have to run the custom target after the wrong target Publish,instead, you should use the PublishBuild Target. Then use copy task to copy the file into Puplish folder during you execute the clickonce operation.
After all, you can try my sample which l have tested successfully in the ProjectB.csproj file.
<Target Name="CopyToPublish" AfterTargets="PublishBuild">
<ItemGroup>
<ResourceFiles Include="xxxxxxx\ProjectA.resources.dll" /> // the path of the ProjectA.resources.dll
</ItemGroup>
<Copy SourceFiles="#(ResourceFiles)" DestinationFiles="#(ResourceFiles->'$(PublishUrl)\de\%(RecursiveDir)%(Filename)%(Extension)')" />
</Target>
Update 2
After l do some research, I found that when VS put files into Clickonce Manifest, it runs the targets(GenerateApplicationManifest, GenerateDeploymentManifest,GenerateManifests and so on) sequentially.These are the targets that act as the concrete execution of the file into the manifest. So when you use use your BeforePublish target to put the extra file as an item, you should run before the target. So please try this:
<Target Name="BeforePublish" BeforeTargets="GenerateApplicationManifest">
<ItemGroup>
<AdditionalPublishFile Include="xxxxxxx\de\ProjectA.resources.dll">
<Visible>False</Visible>
</AdditionalPublishFile>
</ItemGroup>
<Touch Files="#(IntermediateAssembly)" />
<CreateItem Include="#(AdditionalPublishFile)" AdditionalMetadata="TargetPath=de\%(FileName)%(Extension);IsDataFile=false">
<Output TaskParameter="Include" ItemName="_DeploymentManifestFiles" />
</CreateItem>
</Target>
When you publish the project, the ProjectA.resources.dll will display in the ProjectB.manifest file successfully. But the extra file will not display in the Property UI Publish-->Application Files, l think this is a UI display problem that does not affect the output of this file.
Hope it could help you.
I have config files: confing.yml and scenarios.yml that are in the /config/ folder in my source. I use this code to find the configurations at the expected location using relative path:
string currentAssblLoc = Path.GetDirectoryName(AppDomain.CurrentDomain.BaseDirectory);
string confFileLoc = currentAssblLoc + #"\config\config.yaml";
When I compile the app, the executable is moved to the debug folder, but the config files are not.
Question: taking into account the release version of the compiled assembly and the debug mode in which developers are writing code where should I place the config files. Is there a way for these files to be moved into the appropriate folders that can be defined in the project properties and what are some recommended practices around that.
Update: I see that the contents of the config folder are included in the .csproj file
<ItemGroup>
<None Include="App.config" />
<None Include="config\config.yml" />
<None Include="config\scenarios.yml" />
<None Include="packages.config" />
</ItemGroup>
I have been using SlowCheetah for many years. It can transform different config files depending on the Configuration settings. You can transform config files for development, staging and releases without having to manually change anything.
You can replace certain tags or complete sections. Config files are put into the appropriate configuration output directory defines in the properties for the configuration.
You can also use the Post Build options to copy files around after the build.