-
I've been diving into how single file publish works as I had an idea of how to embed other digital assets (e.g. zip/7-zip files) into a published single file Looking at the code as listed below. All the parts are there to be able to use this for my purpose, but a bit frustratingly the way options are defined do not allow me to do this. All I needed was to be able to say include "unknown" content without self-extracting, unfortunately inclusion and self-extration are tied together it seems (?). My question then is how I can possibly circumvent this in some way? I tried hacking this by changing the assets extension to Why not allow devs to use this feature to embed other "unknown" assets (at own risk/peril etc.) so one can avoid going down the path of having to embed such assets as content in a managed dll that has memory consumption issues. This is important for my use case due to 32-bit limits. And don't want to put GBs in temp directory.
|
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
The main reason is that we would have to define new APIs which would let you access these assets. .NET already has something similar - embedded assets in managed assemblies and the relevant APIs for that. Defining new APIs for basically a very similar purpose feels wrong. There are other discussions on allowing to access these through special formed paths (Windows allows this in some cases to access Win32 resources), but that comes with a lot of challenges - there are lot of APIs in .NET which access file path and it would confusing to support these new paths only in some of them (and doing them all is very expensive). The other consideration is compatibility - is you use embedding into managed assemblies the code will work regardless if it's published as single-file or not (so debug builds will work the same as published app). Any APIs which only work in single-file mode would not have that property and testing the code using them would be much more difficult. If you're on Windows you could see if embedding them as Win32 resources works - you can access those via PInvokes easily. But I don't know if the same 2Gb limit applies there as well. |
Beta Was this translation helpful? Give feedback.
-
I managed to get this working by going deep into the bowels of the bundling code. Here a short recap. In the project where we want to embed some extra files the following targets is added. Note how <PropertyGroup>
<PublishSingleFile>true</PublishSingleFile>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
<TraceSingleFileBundler>true</TraceSingleFileBundler>
<FilesToBundleAddArchivesEnable>true</FilesToBundleAddArchivesEnable>
</PropertyGroup>
<Target Name="FilesToBundleAddArchives" BeforeTargets="GenerateSingleFileBundle" DependsOnTargets="PrepareForBundle"
Condition="$(FilesToBundleAddArchivesEnable)">
<Message Text="PublishDir '$(PublishDir)'" Importance="high" />
<ItemGroup>
<ArchivesToAddToFilesToBundle Include="$([System.IO.Path]::GetFullPath($(PublishDir)))\..\publish-archives\*.7z" />
<!-- Add metadata for the relative path for GenerateBundle -->
<ArchivesToAddToFilesToBundle RelativePath="%(ArchivesToAddToFilesToBundle.FileName)%(ArchivesToAddToFilesToBundle.Extension)" />
</ItemGroup>
<Message Text="RelativePath: %(ArchivesToAddToFilesToBundle.RelativePath) - Items: @(ArchivesToAddToFilesToBundle)" Importance="high" />
<ItemGroup>
<FilesToBundle Include="@(ArchivesToAddToFilesToBundle)" />
</ItemGroup>
</Target> To then fix the bundle meta-data to avoid the <!--
IncludeAllContentForSelfExtract=true will cause all embedded content in
single file to be self-extracted to
`C:\Users\<USERNAME>\AppData\Local\Temp\.net\<EXE>\<HASH>` for our
archives of GB size this is unfortunate as takes up space but also since
this happens on app start so that is sluggish.
To fix that a custom task modifies the bundle manifest to avoid this
extraction for all but the native library files as normal, while still
embedding the archives.
-->
<UsingTask TaskName="SingleFileBundleManifestModifyTask"
TaskFactory="RoslynCodeTaskFactory"
AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.Core.dll">
<Task>
<Code Type="Class" Language="cs" Source="$(MSBuildThisFileDirectory)../SingleFileBundleManifestTasks/SingleFileBundleManifestModifyTask.cs" />
</Task>
</UsingTask>
<Target Name="SingleFileBundleManifestModifyTask-Installer"
AfterTargets="GenerateSingleFileBundle">
<Message Text="MSBuildToolsPath: $(MSBuildToolsPath)" Importance="high" />
<SingleFileBundleManifestModifyTask BundlePath="$(PublishDir)\$(TargetName).exe"
FileEntryRelativePathEndsWith=".7z"
FileEntryFileTypeToChange="Unknown"
FileEntryNewFileType="Assembly" />
</Target> The task C# code is based on bundler code e.g. see and follow code from: Basically, the task This trick can be used to embed any kind of file without it being self-extracted. The contents can then be accessed via the And using a |
Beta Was this translation helpful? Give feedback.
I managed to get this working by going deep into the bowels of the bundling code. Here a short recap. In the project where we want to embed some extra files the following targets is added. Note how
IncludeNativeLibrariesForSelfExtract
is set totrue
, as discussed in question above.