packing image resource into nuget library and accessing it [duplicate] - wpf

This question already has answers here:
WPF - Import image as resource
(3 answers)
How to get a Uri of the image stored in the resources
(2 answers)
Closed 10 days ago.
I have a nuget package which contains some logos which should be accessible.
The logos are located in the Resources Folder:
[![enter image description here][1]][1]
The logos are set up as embedded resource. I can access them with the following pack url when I add the project reference:
<Image Source="pack://application:,,,/Dexie.Space.Net;component/Resources/dexie_medium.png"></Image>
this does not work when I add the nuget package instead.
I have done some research and edited the project file as such withiout success:
</EmbeddedResource>
<EmbeddedResource Include="Resources\dexie_black_medium.png">
<Pack>True</Pack>
<PackagePath>Resources/dexie_black_medium.png</PackagePath>
</EmbeddedResource>
<EmbeddedResource Include="Resources\dexie_medium.png">
<Pack>True</Pack>
<PackagePath>Resources/dexie_medium.png</PackagePath>
</EmbeddedResource>
<EmbeddedResource Include="Resources\dexie_white_medium.png">
<Pack>True</Pack>
<PackagePath>Resources/dexie_white_medium.png</PackagePath>
</EmbeddedResource>
<EmbeddedResource Include="Resources\duck_black_medium.png">
<Pack>True</Pack>
<PackagePath>Resources/duck_black_medium.png</PackagePath>
</EmbeddedResource>
<EmbeddedResource Include="Resources\duck_medium.png">
<Pack>True</Pack>
<PackagePath>Resources/duck_medium.png</PackagePath>
</EmbeddedResource>
<EmbeddedResource Include="Resources\duck_white_medium.png">
<Pack>True</Pack>
<PackagePath>Resources/duck_white_medium.png</PackagePath>
</EmbeddedResource>
so either the package path or my pack url seems incorrect to me.
[1]: https://i.stack.imgur.com/kaQ0d.png

Related

How to flatten Nuget package contentFiles?

Nuget package issues - buildAction, copyToOutput, flatten are ignored
Package project (ThisProject.vbproj)- .Net Standard Library 2.0, .nuspec file:
<references>
<reference file="ThisProject.dll"></reference>
<reference file="First.dll"></reference>
<reference file="Second.dll"></reference>
<reference file="...."></reference>
</references>
<contentFiles>
<files include="any/any/*" buildAction="Content" copyToOutput="true" flatten="true" />
</contentFiles>
</metadata>
<files>
<file src="contentFiles\any\any\First.dll" target="lib\any\any\First.dll"></file>
<file src="contentFiles\any\any\Second.dll" target="lib\any\any\Second.dll"></file>
<file src="contentFiles\any\any\....dll" target="lib\any\any\.....dll"></file>
</files>
When importing in .net ClickOnce Framework 4.6.1 Project, the contentFiles are still in the subfolders (flatten is ignored), Build Action and CopyToOutputDirectory are the defaults (buildAction,copyToOutput are ignored)
Read all the documentation I could find e.g.
https://learn.microsoft.com/en-us/nuget/reference/nuspec
What am I doing wrong?
I think you have some misunderstanding about this part.
First, contentFiles works for new-sdk projects(Net Core and Net Standard) with PackageReference nuget management format rather than Net Framework project with packages.config nuget management format.
And contentFiles works for content files rather than lib folder. So you should not pack these dll files on target="lib\any\any\.....dll". You should pack them into contentFiles folder.
Use this:
<contentFiles>
<files include="any/any/*" buildAction="Content" copyToOutput="true" flatten="true" />
</contentFiles>
<files>
<file src="xxx\First.dll(the physical, relative path of the dll on your project folder)" target="contentFiles\any\any\First.dll"></file>
<file src="xxx\Second.dll(the physical, relative path of the dll on your project folder)" target="contentFiles\any\any\Second.dll"></file>
<file src="xxx\....dll(the physical, relative path of the dll on your project folder)" target="contntFiles\any\any\.....dll"></file>
<files>
Then, you should install this nuget package on a Net Core project.
When you finish it, repack the project with nuget pack command, then, before you install the new one, clean the nuget caches first to remove the old previous version. Then, install the new version on a Net Core project and you can see the effect like this:
======================================================================
If you still want to have this function on a Net Framework project, you should pack these files on content node rather than contentFiles.
And you only need to add two lines:
<contentFiles>
<files include="any/any/*" buildAction="Content" copyToOutput="true" flatten="true" />
</contentFiles>
<files>
<file src="xxx\First.dll(the physical, relative path of the dll on your project folder)" target="contentFiles\any\any\First.dll"></file>
<file src="xxx\Second.dll(the physical, relative path of the dll on your project folder)" target="contentFiles\any\any\Second.dll"></file>
<file src="xxx\....dll(the physical, relative path of the dll on your project folder)" target="contntFiles\any\any\.....dll"></file>
<file src="xxx\First.dll(the physical, relative path of the dll on your project folder)" target="content"></file>
<file src="xxx\Second.dll(the physical, relative path of the dll on your project folder)" target="content"></file>
..........
<files>
But these simply cannot change the attributes of the imported file. And for net framework project, changing the property of the files cannot be done on xxx.nuspec file.
You should use <packages_id>.props or targets file.
1) create a file called <packages_id>.props under the build folder on the Solution Explorer, if your nuget package is named as ThisProject.1.0.0.nupkg, you should name it as ThisProject.props so that it will work.
This is mine:
2) add these on the props file:
<Project>
<ItemGroup>
<Content Include="First.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="Second.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
......
</ItemGroup>
</Project>
3) add a line on nuspec file to include the props file into the nupkg.
<file src="build\xxx.props(the physical, relative path of the file on your project folder)" target="build"></file>
4) then repack the nuget package, clean the nuget caches, then install this new one on the Net Framework project with packages.config.
Note: although the Properties window of the imported content file on the solution explorer does not show the changed value and still shows the old one, the files are already copied into the output folder of the project. And it is an UI display issue on Solution Explorer and the changed values are already be used and work well. So you do not have to care much about that.

How to exclude App.config from getting bundled in the .exe in a .net core 3 single-file self-contained WinForms app?

I have a Winforms .NET Core 3 app that I want to publish as a Self-Contained Single-File Deployment
Here is the relevant .csproj file
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<PublishSingleFile>true</PublishSingleFile>
</PropertyGroup>
<ItemGroup>
<!--PackageReferences-->
</ItemGroup>
<ItemGroup>
<!--ProjectReferences-->
</ItemGroup>
</Project>
I am using <RuntimeIdentifier>win-x64</RuntimeIdentifier> so it generates a Self Contained Deployment for Windows x64 and <PublishSingleFile>true</PublishSingleFile> so everything gets embedded in the .exe file.
When publishing by running:
dotnet publish -c Release
I get the .exe and the .pdb files at bin\Release\netcoreapp3.0\win-x64\publish
- MyApp.exe
- MyApp.pdb
What do I need to change in the .csproj file so I get the MyApp.dll.config or MyApp.exe.config whichever is correct next to the .exe so the app actually reads config from it instead of its embedded App.Config?
I have tried adding this
<ItemGroup>
<Content Update="*.config">
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
as hinted by this link Single-file Publish - Build System Interface but it still produces only the two files.
Your question helped me figure out this for me, so thanks.
hopefully this works for you too.
my .csproj looks like
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.0</TargetFramework>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
</PropertyGroup>
<ItemGroup>
<Content Include="*.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</Content>
</ItemGroup>
just done some further testing with a .config file
<ItemGroup>
<None Update="*.config">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</None>
</ItemGroup>
that worked for me, with the other config from above.

WIX Setup doesn't build

I am using the WIX binaries from a local folder instead of the common installation. So i had to overwrite my Paths like this:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<WixToolPath>$(TeamProjectBuildUtilsDir)Tools\WIX\</WixToolPath>
<WixTargetsPath>$(WixToolPath)Wix.targets</WixTargetsPath>
<WixTasksPath>$(WixToolPath)WixTasks.dll</WixTasksPath>
</PropertyGroup>
</Project>
It was working ok, but today i tried it again and get this:
System.IO.FileLoadException" in WixTasks.dll:
> Additional information: The file or assembly
> "file:///D:\Repos\MyProject\BuildUtils\Tools\WIX\candle.exe" or a
> dependency could not be found. To progress is not supported.
> (Exception of HRESULT: 0x80131515)
I am not very expirenced with WIX and don't know what to do. It worked fine.
My VS freezes after this build step.
If you downloaded the WiX binaries .zip, you need to "unblock" the file (remove the stream that indicates it was downloaded from the Internet). .NET won't load files that are marked as coming from the Internet.

How to include heat generated wsx files in a smart way in wix installer?

It's a WPF application, with Wix Installer.
I have resourceses folder and I want to include these files in the installer to put next to the executable. I solved generating a resources.wxs file with necessary information about the files under the resources folder using the heat tool. I managed to includ into the main wxs file. For that reason I modified the .wixproj file, adding a before build target action to generate the wxs and include it in the main wxs.
Concern: .wixproj is kind of hidden, there thing that you cannot modify from visual studio, like adding a before build action (pre build action is a different story)
Question: How can I extract the before build action into a separate file?
The before build action in the .wixproj:
<Target Name='BeforeBuild'>
<Exec Command='"%WIX%bin\heat" dir $(SolutionDir)resources -dr ResourcesDir -var var.ResourcesDir -cg ResourceFilesGroup -gg -g1 -sfrag -srd -out $(ProjectDir)Resources.wxs' />
<ItemGroup>
<Compile Include='$(ProjectDir)Resources.wxs' />
</ItemGroup>
You can extract it into a separate fileā€”most project file types do that already. That's how they provide common targets to all projects of a type. A .wixproj has this:
<Import Project="$(WixVersionTargetsPath)" />
To augment your own, simply:
Create an XML file like:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Target Name='BeforeBuild'>
<!-- tasks -->
</Target>
</Project>
Add an Import element inside the Project element and refer to that file:
<Import Project="custom.targets" />
If such a file primarily has Target elements, the convention is for it to have the file extension ".targets".
But there are two drawbacks with Visual Studio:
Visual Studio caches all the project file dependencies and runs the MSBuild internally. So, it you edit the external file, it won't be part of builds using Visual Studio until the project is next loaded. To quickly unload and reload a project, use the project context menu in the Solution Explorer. Workaround: Call MSBuild yourself.
When Visual Studio loads a project, if it includes non-standard external files, it gives a warning. (You can disable it per user by project file path, in the registry, if I recall.)
As an alternative to calling heat directly, you might want to look at the Harvest* targets that WiX provides. Note: As the documentation says, you don't invoke them directly (they're already invoked by the Build target); You simply add items to the ItemGroup they process and set properties they use.

How can I modify my C# project file so that Resources.resx is compiled into the satellite assembly for my UICulture?

I have a WPF application in C# that may need to be localized in the future. I want to support XAML/BAML localization and conventional resx localization. (The former is useful for most of the code, but some localized content comes from the view model, where it is more straightforward to use resx files.)
I have read the relevant parts of the WPF Localization Guidance. I have set the UICulture property in the msbuild file. I have added the following line to AssemblyInfo.cs:
[assembly: NeutralResourcesLanguage("en", UltimateResourceFallbackLocation.Satellite)]
I understand that I need to copy Resources.resx as Resources.en.resx so that my localized resources get written to the satellite assembly.
I have set the build target on Resources.resx to None and on Resources.en.resx to EmbeddedResource. The custom tool on Resources.resx is PublicResXFileCodeGenerator to generate the strongly typed resources class. I know that the generator only works on a file that doesn't have a culture-specific suffix.
At the moment I must manually keep Resources.resx and Resources.en.resx synchronized. They must be identical. (Rick Stahl explains that here.)
I have tried to modify my C# project file to copy the file automatically. However, I can't get this to work. I'm no msbuild expert! I added the following build target:
<Target Name="BeforeResGen">
<Copy SourceFiles="#(CopyAsLocalizedResources)" DestinationFiles="$(IntermediateOutputPath)Resources.$(UICulture).resx">
<Output ItemName="EmbeddedResource" TaskParameter="DestinationFiles"/>
</Copy>
</Target>
I changed the Build Action for Resources.resx from None to CopyAsLocalizedResources.
I see my Resources.en.resx file being copied to the intermediate directory during build, but my resources aren't found at runtime, and I get an exception. Presumaby they are never being compiled into the satellite assembly.
Can anyone help me achieve this using a modification to the project file?
The compiled language dll is expected to be in a folder named according to the ISO culture code for that culture. This culture-named folder is expected to be in the same directory as the parent assembly.
So, for some foo.dll:
(Default DLL)
bin\foo.dll
(Spanish(Mexico) Resources)
bin\es-mx\foo.Resources.dll
This folder structure and assembly will be made at compilation, so you just need to tweak your post-build action to move the dll in the culture folder to a matching folder in your target directory.
Note that you can perform this move via cp or other command line tools simply by typing the actions you need in the project post-build step box with the project properties in Visual Studio.
Eureka!
<Target Name="CreateLocalizedResources" BeforeTargets="AssignTargetPaths">
<Copy SourceFiles="#(CopyAsLocalizedResources)" DestinationFiles="$(IntermediateOutputPath)Resources.$(UICulture).resx" SkipUnchangedFiles="true" UseHardlinksIfPossible="true">
<Output TaskParameter="DestinationFiles" ItemName="GeneratedLocalizedResources" />
</Copy>
<ItemGroup>
<EmbeddedResource Include="#(GeneratedLocalizedResources)">
<ManifestResourceName>$(RootNamespace).Properties.Resources.$(UICulture)</ManifestResourceName>
</EmbeddedResource>
</ItemGroup>
<Message Text="Generated resources are: #(GeneratedLocalizedResources)" Importance="high" />
</Target>
I set the Build Action on my Resources.resx file to CopyAsLocalizedResources, and the custom build target handles tricking the build into making the proper satellite assembly.

Resources