Multi target net frameworks conflicts - c#

I have a Nuget package project that targets framework netcoreapp2.2. I'm trying to use it for an application that contains other projects targeting frameworks netstandard2.0;netcoreapp3.1.
This is what I currently have in the .csproj for that
<PropertyGroup>
<TargetFrameworks>netcoreapp2.2;netstandard2.0;netcoreapp3.1</TargetFrameworks>
</PropertyGroup>
<ItemGroup Condition="'$(TargetFramework) '=='netcoreapp2.2'">
( ........ )
In the classes I get the conflicts I'm using the conditional directive
##if true
1. But I'm getting compile errors because some of the extensions I'm using here are not available in one of the frameworks above.
*[Solved] I get this error:
Error CS0006 Metadata file 'C:\Users\user\source\repos\workspace\project\bin\Debug\netstandard2.0\project.dll' could not be found project.Test (netcoreapp2.2)
Is there any way I can target multiple frameworks to be able to download the NuGet package in the other projects?
Any ideas for a better approach?
Thanks
Update:
Error #2 The file project.dll didn't exist. It wasn't autogenerated by rebuilding the project. Adding the file manually solved it.

Related

MSBuild Conditional PackageReference based on .Net TargetFramework

INTRODUCTION
I am building a class library which could be used by some legacy applications targetting .Net Framework 4.0 and new applications targetting .Net Framework 4.6.1
I am adding some database/Hibernate new code in the class library that requires .Net Framework 4.6.1. This new code is incompatible with .Net Framework 4.0 because the nuGet package FluentNHibernate 3.1.0 requires .Net Framework 4.6.1 and up. And legacy application does not require this functionnality.
WHAT I AM TRYING TO ACHIEVE
I am attempting to conditionnaly build the class library so one code base and the master git branch can be used to build a version compatible for either one or the other application.
So far, I have been able to:
Define a constant indicating the target framework (FWK40)
for use within .cs code to adjust code to target framework
Conditionally define the targetted framework (TargetFrameworkVersion)
Exclude files from build when not under the right TargetFrameworkVersion
Here is what the .CSPROJ looks so far (emphasis for the relevant adjustments):
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug.Net40|AnyCPU'">
<!-- Set target framework here -->
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\Debug.Net40\</OutputPath>
<!-- Define Build-time constant here -->
<DefineConstants Condition=" '$(TargetFrameworkVersion)' == 'v4.0'" >FWK40</DefineConstants>
</PropertyGroup>
<ItemGroup>
<-- Conditionally include .cs files here -->
<Compile Include="Database\GeneralSQL.cs" Condition="'$(TargetFrameworkVersion)' != 'v4.0'" />
<Compile Include="Database\NamingStrategy.cs" Condition="'$(TargetFrameworkVersion)' != 'v4.0'" />
<ItemGroup>
<ItemGroup>
<-- In THEORY conditionally include PackageReference here -->
<PackageReference Include="FluentNHibernate" Condition="'$(TargetFramework)' != 'net40'" >
<Version>3.1.0</Version>
</PackageReference>
</ItemGroup>
THE RESULT SO FAR
What is happenning, is I am getting a nuGet error saying:
NU1202: Package FluentNHibernate 3.1.0 is not compatible with net40 (.NETFramework,Version=v4.0). Package FluentNHibernate 3.1.0 supports:
Failed to restore C:\_projets\repos\TestSolution\TestLibrary\TestLibrary.csproj (in 19 ms).
NuGet package restore failed. Please see Error List window for detailed warnings and errors.
Not withstanding this error, the assemblies all are generated properly, the DLL Class Library itself, as well as an EXE Console application using that class library AND so far they run properly.
THE PROBLEM
I haven't been able to conditionnaly include nuGet a PackageReference.
AND The nuGet error still causes MSBuild.exe to fail, which prevents the CI/CD pipeline to work properly..
WHAT I HAVE TRIED
I have tried many many ways to get rid of nuget NU1202 error message.
#1 I have tried initially with other conditions based on $(TargetFrameworkVersion) which works througout the .csproj but to no avail.
#2 According to official documentation, nuGet ReferencePackage only supports conditions based on $(TargetFramework) adding-a-packagereference-condition as shown in the sample .csproj above. YET THIS STILL DOES NOT WORK.
I haven't been able to figure out so far what exactly the Property TargetFramework looks like. I ran MSBUILD.EXE in Verbosity level diagnostics, which dumps all the Properties, but TargetFramework wasn't listed (while others were)
I have tried to "reverse" the condition == 'net461' so that if the expected value is incorrect, it won't be included and the error would disappear => no effect, errors still there
#3 I have tried to define myself the TargetFramework property
<!-- Set target framework here -->
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
<TargetFramework>net40</TargetFramework>
The outcome would be much worse!
Visual Studio did not like it, the "Configuration Manager" broke down
it would not allow to set a specific Configuration for a project.
changing from Debug.Net40 to any other configuration (or loading the project) would show a nasty error message
Current solution contains incorrect configuration mappings. It may cause projects to not work properly
And the csproj was definitely not loaded properly either and project would be skip the build step.
WHERE I AM AT NOW
I am really stuck! Can't seem to find a way to make this work.
I would hate to have to have a branch master40 and a branch master just to handle this.
I would hate to have to have two csproj different files, unless I can somehow manage to share/include one into the other AND Visual Studio would not complain
The really really right thing would be to make the conditions on the ReferencePackage to actually work as intended.
What you want is multi-targeting.
The documentation you link seems to be only applicable for SDK-style projects.
AFAIK, multi-targeting is not available with the legacy-style project format.
I suggest migrating to the SDK-style project format.
A lot of things are much simpler there, not to mention better documented.
You can use a tool to do this, like hvanbakel/CsprojToVs2017 or dotnet/try-convert. Don't be fooled by its name and wrong usage of terminology.
(since this is also mixed up on SO all the time: yes, you can use the SDK-style format with .NET Framework TFMs; SDK-style has nothing to do with either TFM or Visual Studio version, but only with minimum required MSBuild version).
Once you have done that for your particular project, the documentation for multi-targeting applies and you can use Condition on $(TargetFramework) just like you have already done, in both your PackageReference and the Compile item group and pretty much anywhere you want.

How to fix NuGet package Razor runtime compilation Error?

After reading through several answers (.NET Core 3.0 - Preview 2 - Razor views don't automatically recompile on change) that recomend installing Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation NuGet package to get back runtime compilation, I tried the suggested solutions but the project gets the following error message simply by installing the package without even using AddRazorRuntimeCompilation():
The project "project name" must provide a value for configuration
double clicking in the error leads to the following path:
C:\Users....nuget\packages\microsoft.aspnetcore.razor.design\2.2.0\build\netstandard2.0\Microsoft.AspNetCore.Razor.Design.CodeGeneration.targets
But there is no indication as to what is wrong with this file
Add <RazorCompileOnBuild>false</RazorCompileOnBuild> to your .csproj file. That should allow you to build the project.
You also might need <MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish> for publishing to a server.
See example below:
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
...
<RazorCompileOnBuild>false</RazorCompileOnBuild>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
...
</PropertyGroup>
Found this property from this answer on a related question.

Visual Studio not copying dependencies | Could not load file or assembly

I'm writing a class library to abstract our company's Database functions, but when the code gets to instantiating one of my database objects we get a:
FileNotFound Exception:
Could not load file or assembly 'MySql.Data,
Version=8.0.13.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' or
one of its dependencies. The system cannot find the file specified.
The MySql.Data Dependencies as stated on the website are:
.NETStandard 2.0 Google.Protobuf (>= 3.5.1)
System.Configuration.ConfigurationManager (>= 4.4.1)
System.Security.Permissions (>= 4.4.1)
System.Text.Encoding.CodePages (>= 4.4.0)
But all of them are installed automatically.
The NuGet package is MySql.Data (8.0.13) (which installs successfully)
Project is a .NET Standard 2.0 class library
There are no compile errors or even warnings; just the above error at run-time.
Have looked through Could not load file or assembly or one of its dependencies which advises checking where the dependencies are not being found - so I did - but it doesn't say how to fix the missing reference when you've found where it is?
Using Process Monitor I was able to find the failed CreateFile operation DLL calls, referencing ...\TestingGUI\bin\Debug\MySql.Data\MySql.Data.dll which, manually checking, is not there.
The project that runs is a WinForms app that references another .NET Standard class library (essentially a middleman) which then references the database library which depends on MySql.Data.
Doing a search in the whole solution directory, there are no MySql.Data.dll files, especially after a full solution build.
Here is my csproj file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<RootNamespace>App1.Database</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MySql.Data" Version="8.0.13" />
</ItemGroup>
</Project>
So, who's a .NET Wizard?
UPDATE:
So it turns out the code works fine when run from a .Net Core console app, but only has the error when referenced from a .NET app (specifically winforms). So I've given up having a GUI for now and am just using a .NET Core console app. I thought .NET Standard was compatible with everything, but maybe not? Anyway, I will keep my question here for anyone else having troubles.
UPDATE 2:
Thanks to #Itay Podhajcer's answer we managed to get it working with .NET Winforms by also including the NuGet package there.
I remember encountering the same issue, I think it was related to the new nuget referencing model.
Try adding the missing nuget package directly to the WinForms project.Far from ideal solution, but it should work.
Hope it helps!
Visual Studio not copying dependencies | Could not load file or assembly
It seems the dependencies and assembly are not copied to the output folder. You can check the thread for some more details:
PackageReference is missing copy files to output feature
To resolve this issue, you can try to following workaround:
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
Hope this helps.

Assembly Version of [MyMvcProject].Views.dll

When compiling a .net core Web MVC project VS / Compiler creates an assembly called [MyMvcProject].Views.dll with an AssemblyFileVersion of 0.0.0.0.
Is it possible to change the Version for this generated file (and maybe also change other Assembly properties?
UPDATE
I've added Manually AssemblyInfo.cs and edited my csproj with <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
With this constellation it seems that the data is not propagated to [MyMvcProject].Views.dll
I would like to stick with AssemblyInfo.cs because I share the this file over several projects. (Unless there's another solution to have consistent Assembly Versions over many projects).
Still would like to give [MyMvcProject].Views.dll a specific version.
Any idea?
I would like to stick with AssemblyInfo.cs because I share the this file over several projects. (Unless there's another solution to have consistent Assembly Versions over many projects).
You can use a Directory.Build.props file to achieve this. This file is recognised automatically by the dotnet build system (it's part of MSBuild) and will apply to all projects within the same directory or lower. If you want to apply a Version property for an entire solution, for example, you can drop a Directory.Build.props file next to the .sln file, with the following contents:
<Project>
<PropertyGroup>
<FileVersion>1.0.0.404</FileVersion>
</PropertyGroup>
</Project>
As you might expect, this AssemblyFileVersion property will also apply to your [MyMvcProject].Views.dll assembly.
Here's a detailed list of the AssemblyInfo properties you can specify when using this approach: AssemblyInfo properties.
Addition by #gsharp:
If there's also a version set in the project properties, then the project version will "win" over the Directory.Build.props version.
Go to your project "Properties" and on "Package" tab you have most of the properties that are in AssemblyInfo in classic .Net Framework projects like "Assembly version" and "Assembly file version".
Also you could try to use this command to build your project: dotnet publish /p:Version=1.2.3

Type not found Microsoft.EntityFrameworkCore in .NET Standard project

I am having a total nightmare getting Entity Framework Core working in my .NET standard project! I am using .NET Standard 2
I can install the package fine (Microsoft.EntityFrameworkCore.SqlServer)
However, when I build my application although it compiles, I get the error below
Could not load file or assembly 'Microsoft.EntityFrameworkCore, Version=2.0.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' or one of its dependencies. The system cannot find the file specified.
Has anyone ever had this? I wasnt expecting this to be such a pain just to use Entity Framework in .NET Standard lol
I cant see any dlls related to this in my output folders
My application is hosted within service fabric, but I am not sure thats anything to do with it
Paul
I am assuming there is a bug either with Nuget or Visual Studio
I ended up having to manually copy all the dlls!!
Try to add this into your .csproj file which contains reference to the
Microsoft.EntityFrameworkCore.SqlServer
<PropertyGroup>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>

Categories