.NET Core - Image resources not included / compiled in library - c#

I would like to include some PNG image files into an assembly (.dll) for use in a WPF application. We previously targeted .NET Framework 4.8 which worked fine but since migrating the project to .NET Standard 2.1 the resources are being ignored.
Using the .NET Framework 4.8 does store the resources as wanted, which means that there is a [AssemblyName].g.resources entry containing a directory-like structure with the images in it. When switching to "netstandard2.1" as target platform, the resources are not included.
The .csproj file looks like this:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<OutputPath>bin\$(Configuration)\</OutputPath>
<ApplicationIcon />
<Win32Resource />
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>none</DebugType>
<GenerateSerializationAssemblies>Off</GenerateSerializationAssemblies>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\AssemblyInfo.App.cs" Link="Properties\AssemblyInfo.App.cs" />
</ItemGroup>
<ItemGroup>
<Resource Include="**\*.png" />
</ItemGroup>
</Project>
The expected result is a resource hierarchy compiled into the library file so that the images can be accessed directly from .xaml. We did this successfuly with .NET Framework as target platform but it won't work with .NET Standard 2.1 or .NET Core 3.0.

To fix it you just need to change
<Project Sdk="Microsoft.NET.Sdk">
to
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
in your project file.
Here are the details and root cause of this problem.

Related

How to add UIAutomationClient.dll and UIAutomationTypes.dll to .Net Core 5.0 project?

How to use UIAutomationClient.dll and UIAutomationTypes.dll in .NET 5.0 project since there is no nuget package available!
I'm trying to convert a .NET Framework 4.8 project to .NET 5.0
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>net48;net5.0-windows</TargetFrameworks>
<UseWindowsForms>true</UseWindowsForms>
<LangVersion>9.0</LangVersion>
</PropertyGroup>
</Project>
This .csproj is enough to use System.Windows.Automation (UIAutomation) in net5
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
</PropertyGroup>
<ItemGroup>
<FrameworkReference Include="Microsoft.WindowsDesktop.App.WPF"/>
</ItemGroup>
</Project>

use .net core sdk in MSBuild project

I have a PCL-project with different functions and classes for each platform. I want to implement .net core support now. But I cant use controls like UserControl because the Microsoft.NET.Sdk.WindowsDesktop SDK isn't referenced. The .net framework is easy to implement because I only have to reference each assembly... But in .net core, I can't reference the assembly...
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;xamarin.ios10;xamarin.mac20;xamarin.tvos10;monoandroid10.0;tizen40</TargetFrameworks>
<TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">uap10.0.17763;net472;netcoreapp3.1;$(TargetFrameworks)</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('net4')) And '$(OS)' == 'Windows_NT' ">
...
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System.Xaml" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netcoreapp3')) And '$(OS)' == 'Windows_NT' ">
...
<SDKReference Include="Microsoft.NET.Sdk.WindowsDesktop" />
</ItemGroup>
That's my executable app, referencing the PCL-project above;
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<ProjectReference ...... />
</ItemGroup>
</Project>
I already tried this to reference the SDK but its not working.
<SDKReference Include="Microsoft.NET.Sdk.WindowsDesktop" />
I want to implement .net core support now. But I cant use controls
like UserControl because the Microsoft.NET.Sdk.WindowsDesktop SDK
isn't referenced. The .net framework is easy to implement because I
only have to reference each assembly... But in .net core, I can't
reference the assembly..
After doing a deep research, I found that Microsoft.NET.Sdk.WindowsDesktop cannot be used by SDKReference.
As a suggestion, you could create a custom targets file and then import it into your PCL-project to use the Net Core SDK.
1) create a file called custom.targets in your PCL project folder.
2) Then add these in custom.targets:
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
</Project>
3) import this in xxx.csproj file of PCL-Project.
<Import Project="$(ProjectDir)custom.targets" Condition=" $(TargetFramework.StartsWith('netcoreapp3')) And '$(OS)' == 'Windows_NT' "/>
4) Then restart your project. Although there are some warnings that reminds you that some sdks are repeatedly quoted, you can ignore them and it will not have any impact on your project.
You can check this, which works well in my side.

Build error when packaging multiple nuget targets

I'm attempting to make a Nuget package for multiple framework targets (.netstandard20 and net46). I am able to build the solution and the outputs appear on disk as expected, but whenever I try to package them (Visual Studio 2019 or msbuild directly), I'm getting the following error:
error MSB4057: The target "_GetBuildOutputFilesWithTfm" does not exist in the project.
I'm not using a .nuspec file and the developer packages of my target frameworks are installed correctly.
Here's my .csproj (with nuget metadata excluded for brevity) - it's pretty basic:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net46</TargetFrameworks>
<ReleaseVersion>1.0</ReleaseVersion>
<PackageVersion>1.0</PackageVersion>
...
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType></DebugType>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework)'=='net46'">
<PackageReference Include="NuGet.Build.Tasks.Pack" Version="5.2.0" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)'=='netstandard2.0'">
<PackageReference Include="NuGet.Build.Packaging" Version="0.2.2" />
</ItemGroup>
</Project>
Does anyone have any ideas??
Thanks
Removing references to NuGet.Build.Tasks.Pack and NuGet.Build.Packaging allows targeting only .NET Standard 2.0 and getting the desired behavior.

.NET: Different target frameworks via project configuration

I would like to have two different .net framework targets via configuration in Visual Studio 2015. While for references, you can edit the CSPROJ file and add a conditions, this does not seem to work for the TargetFrameworkVersion in the first PropertyGroup of the file. I have the impression that any Condition in that element causes VS to completely ignore this element and to fall back to the default value of "v4.0".
Is there any way I can get different target framework versions for different configurations?
This is what I tried in the CSPROJ file:
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
...
<!-- this is what VS2015 would put into the file:
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
-->
<!-- this is what does not work: -->
<TargetFrameworkVersion Condition="'$(Configuration)' == 'OLD_Debug' OR '$(Configuration)' == 'OLD_Release'">v3.5</TargetFrameworkVersion>
<TargetFrameworkVersion Condition="'$(Configuration)' == 'NEW_Debug' OR '$(Configuration)' == 'NEW_Release'">v4.0</TargetFrameworkVersion>
...
</PropertyGroup>
...
</Project>
A similar approach with conditions for the assembly references works fine.
EDIT
I found a similar Stackoverflow question:
Targetting multiple .net framework versions by using different project configurations and tried the approach suggested in the non-accepted answer to remove the TargetFrameworkVersion from the first PropertyGroup block, and edit the later <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'OLD_Debug|AnyCPU' "> blocks to contain it, but my assembly is still compiled for framework 3.5 no matter which configuration I use. At least if I look at the assembly from Powershell using [System.Reflection.Assembly]::LoadFrom("C:\PATH\MyAssembly.dll").ImageRuntimeVersion, I always get version 2, not 4.
The approach found in this answer to a similar question works:
Keep the first PropertyGroup without configuration specific settings, remove the TargetFrameworkVersion element from it. And add the TargetFrameworkVersion settings to the configuration specific PropertyGroups which are in the file anyway, just double them for debug/release:
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
...
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'OLD_Debug|AnyCPU' ">
...
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'OLD_Release|AnyCPU' ">
...
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NEW_Debug|AnyCPU' ">
...
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'NEW_Release|AnyCPU' ">
...
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
</PropertyGroup>
...
</Project>
I verified this as follows:
My assembly references version 2.0.0.0 of the mscorlib assembly for the 3.5 framework (OLD_... configurations), and version 4.0.0.0 of mscorlib for the 4.0 framework (NEW_... configurations).
Using ILSpy, I found that the 3.5 version of my assembly has no attribute for the target framework, as this was only introduced since version 4, but the version 4 framework appears as an attribute of the assembly:
[assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")]

How can a project be built as a portable or a normal class library depending on the selected configuration?

Context: We have a common library project called 'THEPROJECT' that is shared with a Xamarin mobile solution and a web project in visual studio. This shared library is a PCL Profile259 due to restrictions in Xamarin. In our web application solution we would like to mark the data models with the appropriate attributes for DataContext to work correctly (as we want to use LinqToSql).
Attempted Solution: We decided to look into the project for 'THEPROJECT' and change the msbuild in a way that would allow it to exist in a state of portable library / normal class library depending on the selected configuration in visual studio.
We have looked at the solution in this post however it is only part of the solution. We can get the project to exist as one or the other, however it requires a manual change to the project file. Now we get the error loading the following project. The for a portable project must be '.NETPortable'.
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">DebugDesktop</Configuration>
<Platform Condition="'$(Platform)' == ''">AnyCPU</Platform>
<ProjectGuid>{426E7BD8-9DA8-4E15-9512-72E7C632B037}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>THEPROJECT</RootNamespace>
<AssemblyName>THEPROJECT</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<MinimumVisualStudioVersion>10.0</MinimumVisualStudioVersion>
<BuildMode>Desktop</BuildMode>
</PropertyGroup>
<!-- Define the Build Configurations -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugDesktop|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Desktop\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<BuildMode>Desktop</BuildMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseDesktop|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Desktop\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<BuildMode>Desktop</BuildMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugPCL|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\PCL\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
<BuildMode>Portable</BuildMode>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleasePCL|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\PCL\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<BuildMode>Portable</BuildMode>
</PropertyGroup>
<!-- Determine the correct properties for PCL/Desktop -->
<Choose>
<When Condition=" '$(BuildMode)' == 'Portable' ">
<PropertyGroup>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
<TargetFrameworkIdentifier>.NETPortable</TargetFrameworkIdentifier>
<DynamicImportPath>$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets</DynamicImportPath>
</PropertyGroup>
</When>
<When Condition=" '$(BuildMode)' == 'Desktop' ">
<PropertyGroup>
<FileAlignment>512</FileAlignment>
<TargetFrameworkProfile />
<DynamicImportPath>$(MSBuildToolsPath)\Microsoft.CSharp.targets</DynamicImportPath>
</PropertyGroup>
<ItemGroup>
<Reference Include="System.Data.Linq" />
</ItemGroup>
</When>
</Choose>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=8.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\..\mobileapplication\packages\Newtonsoft.Json.8.0.2\lib\portable-net40+sl5+wp80+win8+wpa81\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\sqlite-net-extensions\SQLiteNetExtensions\SQLiteNetExtensions-PCL.csproj">
<Project>{f723017d-ede5-49cc-a84f-881c067c6004}</Project>
<Name>SQLiteNetExtensions-PCL</Name>
</ProjectReference>
<ProjectReference Include="..\..\sqlitenetpcl\src\SQLite.Net\SQLite.Net.csproj">
<Project>{4971d437-0694-4297-a8cc-146ce08c3bd9}</Project>
<Name>SQLite.Net</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(DynamicImportPath)" />
<!-- Source/Resx etc... -->
</Project>
To answer the question about making a project be "Portable" or "Normal" depending on the configuration, when the error that pops up is something about the <TargetFrameworkIdentifier> must be .NETPortable:
Remove all the <ProjectTypeGuids> from the configuration.
Those project type GUIDs give Visual Studio some GUI things that have to do with portable projects only, so when the configuration is not portable it causes the error you got. But since you're comfortable editing the XML, you obviously don't need that stuff. Plus you can continue to use the GUI to edit project properties with the project type GUIDs removed.
At least as of Visual Studio 2015.
When you create a Portable Class Library you need to create your library as a Windows 8.1 Portable Library you can't use Universal Libraries for this, which it sounds like you did by the constraints of Xamarin. The Windows 8.1 Portable Library is a kind of hybrid library that allows classic .net to communicate with the new lightweight versions of .net.
The issue with the Portable Class Library is it can't reference a a Classic Class Library via project reference, you can only reference it via DLL reference. You do not need to mess around with the XML if you are uncomfortable editing that file just find the compiled DLL and add the reference manually. If you choose to do this you will need to manually update the build dependencies or you may have broken references.
It seems like the issue isn't entirely in your .csproj but it is also in your project.json. I have been noticing visual studio not generating the proper project.json file. I have to tinker with the targets in the UI to get it to generate correctly. Once I get the initial project.json to generate I have no other issues.
Prior to doing anything we need to wire up our Portable Class Library to handle a Classic Class Library. The first step is updating the target framework from the properties to target .net 4.5 or whatever version you prefer.
Once you do this confirm that the project.json file looks something like this:
{
"supports": {},
"dependencies": {},
"frameworks": {
".NETPortable,Version=v4.5,Profile=Profile259": {}
}
}
Once your Portable Class Library is targeting the correct version you can then add a DLL reference to the compiled .net 4.5 assembly. I have made no additional changes to the csproj file for the portable class library but here is the source to that so you can take a look.
Notice how the ClassLibrary1 is referenced:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{7C4EB968-4C17-438C-B981-97EDC865F312}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PortableLibrary</RootNamespace>
<AssemblyName>PortableLibrary</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Compile Include="Class1.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="ClassLibrary1">
<HintPath>..\ClassLibrary1\bin\Debug\ClassLibrary1.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<None Include="project.json" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>
This should eliminate issues assuming your web project is ASP.NET Core 1.0. If you are running a Classic ASP.NET application you may still have to create the build rules.
TLDR:
Looks like there is an issue with your project.json file, make sure it is getting generated correctly and you can't directly reference .net 4.5 via project reference you have to reference the DLL.

Categories