Referencing .NET Standard csproj project from .NET Framework traditional project - c#

I have a library written against .NET Standard 1.3 which should be compatible with the .NET Framework 4.6.1 runtime. The library uses the new csproj and works fine when referenced by .NET Core projects.
I also have a WPF project on a traditional csproj which should be able to use this library. In Visual Studio 2017 I managed to reference the .NET Standard library and it compiles without errors.
At runtime, it tries to load assemblies which are dependencies of the .NET Standard project and it fails with assembly not found exceptions. And I can see that my output folder doesn't have any of the dependencies indeed.
Is there a way to reference my library in such a way all the required dependencies are copied to the output folder (or an equivalent solution to make the WPF project run fine)?
Note: If I reference manually one by one all the missing dependencies and use runtime assembly version binding I can make it run, but I shouldn't really do this when referencing a project.
This is the full project page: https://github.com/UnoSD/PasswordManager
.NET Standard csproj
WPF package.config
WPF csproj
It currently is a Roslyn problem: GitHub issue

It is an active issue on Roslyn:
https://github.com/dotnet/roslyn/issues/17639
https://github.com/NuGet/Home/issues/4488

You have to specify compiler output for .NET 4.6.1
Put line like below into your csproj in your .NET Standard library project.
<TargetFrameworks>netstandard1.4;net461</TargetFrameworks>
(that should go instead <TargetFramework>netstandard1.4</TargetFramework>)
Build will produce binaries both for .NET 4.6.1 and .NET Core runtime compatible with NET Standard 1.4.

Related

TargetFrameworks in .NET Core

We are upgrading our project to .NET 6 from .NET Framework 4.5. We have a windows form application. Many of windows form commands has been depriciated in .NET 6. So to tackle this, I changed one of the Windows Forms project in the solution from:
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
</PropertyGroup>
to
<PropertyGroup>
<TargetFrameworks>net45;net6.0-windows</TargetFrameworks>
</PropertyGroup>
Now after changing this, I get the below error:
Project <another_project> targets 'net6.0-windows'. It cannot be referenced by a project that targets '.NETFramework,Version=v4.7.2'.
I understand why another_project is throwing this error message which is because the another_project is referenced in this Windows Form project and another_project's TargetFramework is .NET 6. So, I can change the TargetFramework for another_project to include .NET 4.5 as well.
But my question is, if I change this TargetFramework to TargetFrameworks and add multiple Framework there, does that mean my project is not upgrading to .NET 6 completely. Since it's using .net45 to complie/build in those cases, where it's failing to build in .NET 6. How does TargetFrameworks work??
I found the below link also, TargetFramework vs. TargetFrameworks (plural). But was not much helpful to understand this.
I'm assuming that you've upgraded your project files to SDK-style.
<TargetFrameworks>net45;net6.0-windows</TargetFrameworks> will effectively build your project twice - once for .NET 6.0 and once for .NET Framework 4.5.
(I'm not sure why your .NET Framework project is still targeting .NET 4.5 - I would have thought you should have retargeted it to 4.8 a long time ago...)
The output folders for these two targets will be:
For the DEBUG build:
\bin\Debug\net6.0-windows
\bin\Debug\net48
For the RELEASE build:
\bin\Release\net6.0-windows
\bin\Release\net48
Now if you want to reference one of those assemblies in another project, you're going to need to decide which to use, depending on the target framework for the dependent project.
In your case, it seems that you should be referencing the one in the "net6.0-windows" folder, so you should change your other project to reference that.
However, if you want the dependent project to ALSO be multi-targeted, you will need to change the hint path in the dependent project to use a compile variable to select the correct one.
For example, suppose your multi-targeted dependent project currently references a DLL using the following hint path:
<Reference Include="YourLibraryName">
path to referenced dll\bin\debug\net45\YourLibrary.dll
</Reference>
(Where "path to referenced dll" is whatever path is needed to locate the library.)
Clearly that will only reference the DEBUG Net 4.5 version of the library. You want it to reference the correct debug or release version and the correct .Net 4.5 or .Net 6.0 version. To do that, you can change the hint path to:
<path to referenced dll>\bin\$(Configuration)\$(TargetFramework)\YourLibrary.dll
At build time, $(Configuration) is replaced with the correct DEBUG or RELEASE string, depending on whether you're building DEBUG or RELEASE.
Similarly, the $(TargetFramework) will be replaced with the current build target, taken from the <TargetFrameworks>net45;net6.0-windows</TargetFrameworks> setting - either "net45" or "net6.0-windows".
Doing this will cause the correct DLL to be chosen from your multi-targeted project on which this project depends.
Note that this only applies to references using HintPath as above. If you're using project references, things would be different.
Also note that it's also possible (and maybe better) to create a NuGet package which will handle the dependencies etc properly, but that's a whole different story.
TargetFrameworks is used to build same project to multiple frameworks (so you have binary for each of them in output). It's usually used by libraries so they can be consumed by app targeted for different frameworks or, much less frequently, by apps, so they could be run on different machines.
I guess neither of theses is your cases. You just need to rework your app so it uses only features available in .NET Core.
Since you have added both net45 and net6.0-windows to your project it means that it should be compliable for both frameworks (i.e. it will be compiled twice, for each of the target frameworks), but you are trying to add reference to net6.0 project, which can't be used from net45. You need to either upgrade both to net6.0 only, or add net45 to the another_project.
Though usually it is another way around (compared to what you are trying to do), you use multitargeting for library projects (i.e. another_project in this case if I understand correctly) and keep one version for the executables (i.e. WinForms project should keep it's version).

Is there a way to restrict .NET Core projects to generate only .dll as output files when using .NET Core 3.1 sdk

When i build my .NET Core Console Application using .NET Core 3.1 sdk,it generates both .exe as well as .dll as output. When i was using .NET Core 2.1 it was generating only .dll as output. Is there a way to restrict .NET Core 3.1 sdk to generate only .dll as output?
You can control this with the UseAppHost MSBuild setting:
The UseAppHost property was introduced in the 2.1.400 version of the .NET Core SDK. It controls whether or not a native executable is created for a deployment. A native executable is required for self-contained deployments.
In .NET Core 3.0 and later versions, a framework-dependent executable is created by default. Set the UseAppHost property to false to disable generation of the executable.
<PropertyGroup>
<UseAppHost>false</UseAppHost>
</PropertyGroup>
If you want to disable this when building from the command line, instead of setting it within the .csproj, pass the property as an argument. For example:
dotnet build /p:UseAppHost=false
In .NET, the difference between a .exe and a .dll is actually very small. .exe tend to be little more then .dll's with some bootstrap code and a start point (the class whose main method is to be called).
You can use both .NET .exe and .dll as project references. There might be some difference in some fringe details like COM interop, but I do not expect it.
What exactly the compiler will build, depends on it's inputs. Wich includes the project settings. There is a special type of project for library. And with version changes, the proper reading of projects files could be broken. And of course the option that some code is "seperated out" into a .dll is also there. Most programms nowadays are more .dll's then executeables. And it can be beneficial to keep .exe small.

Extra files in the project (NPGSQL)

The question is stupid enough, but it didn’t work with NuGet before. After installing the NuGet package through the console, to connect to PostgreSQL, files appeared that NetFramework should contain. Without copying these files, the project does not start. What to do to get rid of them and not copy them to the directory with the program. In my understanding, these files should be taken from the framework.
See screenshots:
All need files in project C#
My guess is that you have .Net Standard 2.0 libraries/dependencies in your project.
.NET 4.6.1 might add additional runtime dependencies in your output folder:
.NET 4.6.1, 4.6.2, .NET 4.7 and 4.7.1 all have partial .NET Standard
2.0 support in the natively shipped runtimes, but they still are .NET Standard 2.0 compliant by adding additional runtime dependencies into
your output folder to provide the missing functionality. NuGet along
with the runtime targeting handles automatically adding those
dependencies to your projects to provide the needed runtime support
for those extra features. A lot of those assemblies override behavior
from the base framework and .NET uses runtime redirects to route api
calls to the appropriate assemblies rather than than mscorlib.dll or
other system assemblies.
.NET 4.7.2 is the first version of the full .NET Framework that is
fully .NET Standard 2.0 compliant without any additional dependencies.
See: https://weblog.west-wind.com/posts/2019/Feb/19/Using-NET-Standard-with-Full-Framework-NET
In other words, targeting .NET 4.7.2 should get rid of the additional files.

How to deploy C# DLL of hidden NuGet dependency automatically when mixing .Net Standard and .Net Framework?

I have a Visual Studio (2017) C# solution which is structured like this:
Solution
ExeProject
DLLProject
NuGet-Dependency to Stateless package ("Stateless" is the name of the package)
The DLLProject hides the dependency within its interfaces, i.e. the usage of the Stateless library is supposed to be an implementation detail of DLLProject.
The ExeProject accesses only the public interfaces and factories of DLLProject.
Due to reasons which go beyond the scope of this question, ExeProject targets .Net Framework 4.6.1, while DLLProject targets .Net Standard 2.0.
This compiles fine, but when debugging, the Stateless.dll is not found by the executable.
Is it possible to automatically deploy that DLL when linking against DLLProject without adding a Stateless NuGet dependency to the ExeProject?
In .NET Core this transitive NuGet dependencies work automatically.
On .NET Framework, there is a "Copy Local" option for referenced libraries. Make sure that it is set to True for the problematic one.
Update
For your case, .NET Framework App and .NET Standard lib, the setup requires manual modification of the .NET Framework app's .csproj file. Please follow:
Copy all dependencies from .Net Standard libraries to .Net Framework Console application

Alea.Gpu on .NET Standard 2.0 - will this workaround work?

I'm writing a library which has support for GPU acceleration through the Alea.Gpu library, and so far my setup is:
Base .NET Standard 2.0 binary (CPU)
.NET Framework 4.7.1 with Alea.Gpu (GPU)
The idea is that you'd only use the base .NET Standard 2.0 library when on .NET Core/UWP/Whatever, and also include the .NET Framework 4.7.1 library when using a .NET Framework app to leverage the GPU support.
Since Alea.Gpu is cross-platform though (it works with Mono and Xamarin too according to the docs), I thought I'd move all the code in a single .NET Standard 2.0 library, and the user would then be able to check if the GPU features are supported on the current platform before eventually using them.
The problem is that currently the Alea.Gpu NuGet packages doesn't seem to be using the new PackageReference setup, so installing it in the .NET Standard 2.0 library causes the package to be added successfully, but the dependencies being lost in the process.
In practice, I have Alea.Gpu installed but I don't have any namespace in the library (the .dll files aren't there either).
See here: https://github.com/dotnet/standard/issues/481
I have found a workaround that seems to work, even if on .NET Framework only, that just consists of adding these lines to the library .csproj file:
<ItemGroup>
<Reference Include="Alea">
<HintPath>$(NuGetPackageRoot)\alea\3.0.4\lib\net45\alea.dll</HintPath>
</Reference>
<!-- Same for Alea.Parallel -->
</ItemGroup>
My questions are:
Even if the .dll files aren't correctly added to the library, would they still be downloaded upon build, so that they'd still end up in that folder as in the .csproj code, on any other PC too?
Is it safe to say that upon build VS will restore those .dll files in the same net45 subfolder, regardless of the actual platform? I mean, will it automatically fallback to net45 when restoring the packages for the .NET Standard 2.0 library?
Is there any other (better) workaround until Alea.Gpu is updated to use PackageReference so that it will automatically include those .dll files?
Thanks!

Categories