Referencing DLL's between solutions - dll

I've found an interesting issue with using DLL's in .NET Core (.NET Framework works fine). MVCE as follows:
Create an F# (language is irrelevant) .NET Core class library with the following single file (specific code irrelevant as well):
namespace FSharpClassLibrary
module Say =
let hello name =
printfn "Hello %s" name
Create a C# .NET Core class library in a separate solution (very important--it completely works if they are all in the same solution) with the following code:
namespace CSharpClassLibrary
{
public class HelloClass
{
public void Hello(string name)
{
FSharpClassLibrary.Say.hello(name);
}
}
}
Also, add a folder dlls, copy/paste FSharpClassLibrary.dll into it, and add it as a reference to the project (otherwise, the file above won't compile). It's actually not important to move the .dll into the project, but since I'm distributing this second project independently of the first, I need to guarantee the DLL is available.
Finally, add a console app to the same solution as CSharpClassLibrary with the following file:
using System;
using CSharpClassLibrary;
namespace ConsoleApp1
{
public class Main1
{
public static void Main()
{
new HelloClass().Hello("test");
#if DEBUG
Console.Write("Press any key");
Console.ReadKey();
#endif
}
}
}
Finally, go into NuGet and add FSharp.Core version 4.3.4 to both C# projects (just to make sure everything has access to the F# language stuff; not necessary if you create the first class library with C#). Also, I am using VS 15.6; this may or may not be relevant as well.
Set the console app as the startup project and run it. You will get the following error:
System.IO.FileNotFoundException: Could not load file or assembly 'FSharpClassLibrary, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'FSharpClassLibrary, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
at ClassLibrary1.Facade.Hello1.Hello(String name)
at ConsoleApp1.Main1.Main() in C:\Users\***\source\ConsoleApp1\ConsoleApp1\Main.cs:line 11
The most curious part about this is that if I bypass the CSharpClassLibrary library and host FSharpClassLibrary.dll and HelloClass.cs in the ConsoleApp1 project, everything works as expected. The same issue happens if I use two C# DLL's, I used F# because that's what I was working with already.
What I already tried:
Cleaning and rebuilding all projects, making sure each project was referencing the latest build.
Referencing the child (FSharpClassLibrary.dll) from ConsoleApp1 as well as CSharpClassLibrary.dll.
Using the .dll from the obj folder instead of the bin folder (shouldn't matter as far as I'm aware).
Verify that FSharpClassLibrary.dll exists in ConsoleApp1's bin folder.
Double-check that all projects compile to .NET Core, no .NET Standard projects.

Related

Issue with nested DLL referencing in a self-contained .Net Core web app running as a Windows service

The Error
First off, lets start with the error message:
System.BadImageFormatException: 'Could not load file or assembly 'System.Management, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context. (0x80131058)'
In my experience, this type of error usually occurs if the DLL is missing, or it's not in the expected format/version. However, I cannot work out what I need to do to resolve this error.
The Setup
The main project is an ASP.Net Core 3.1 application.
It is configured to be able to run as a Window service and support Web API and MVC frameworks. So my Program.cs looks something like this:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args)
{
var builder = Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
builder.UseWindowsService();
return builder;
}
}
That part all works great, I can run the app as a Windows service and serve razor views and web API endpoints, etc.
However, there are more projects in this solution. I have a couple of .Net 4.6 class libraries projects that are referenced by the service app. So my solution looks something like this:
Service App (NET CORE 3.1)
Lib 1 (NET 4.6)
Lib 2 (NET 4.6)
Service App references Lib 1, and Lib 1 references Lib 2.
Any code is either of these two libraries works fine and can be used by the service app.
The problem is that Lib 2 references System.Management DLL, and this is what is causing the error. Whenever I use a function that uses that DLL, I get the error above.
The Attempts So Far
My attempts so far have including:
Setting the DLL to "copy to output"
Adding the DLL reference directly to the web service app
Manually copying the DLL to the output folder. Both debug, and publish folder (note: publish is set to "self contained" application)
The Question
Basically, how can I resolve this issue? Or at least, how can I further debug the problem to potentially find a solution.
I can't repro this at the time, but I suspect this to be a bug in the way that the self-contained publication process using dotnet publish resolves transitive dependencies.
The point is, your .NET Core 3.1 application doesn't run on .NET Framework, while the library you reference, call it "Lib 2", does.
And your Lib 2 has a reference to the NuGet package System.Management, which, when installed on a project targeting .NET Framework ... does nothing, except making your project reference the .NET Framework reference assembly for System.Management, found in C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1. At runtime, the .NET Framework will load the appropriate assembly from the GAC, but the .NET Core runtime does not do this.
Now when publishing your .NET Core app, MSBuild walks through the dependencies to be copied, and (again, I suppose) looks at the reference assembly and goes "I want that one!" and copies it to your output directory.
But you can't run reference assemblies, you can just reference them, so at runtime, your application blows up with an exception stating exactly that:
Reference assemblies should not be loaded for execution
A workaround, but definitely not a solution, is to reference the same System.Management package from your .NET Core application, where the package will actually extract a DLL containing runnable code, and that one will be copied to your output directory. But this might cause other issues, such as the DLL being overwritten during build with the reference one.
I'd suggest looking at GitHub whether this is a known issue, or that this is something caused by your project setup.

C# CLR Excecption "BadImageFormatException: Could not load file or assembly"

I am using VS 2019 Version 16.8.2
I referred a "CLR Class Library(.NET Core)" project in my "WPF App (.NET)" project and i met a exception:
BadImageFormatException: Could not load file or assembly 'LibCLR, Version=1.0.7646.21580, Culture=neutral, PublicKeyToken=null'. An attempt was made to load a program with an incorrect format.
Let me first talk about how I did it.
Create a "WPF App (.NET)" project "TestCLR"
Add a new "CLR Class Library(.NET Core)" project "LibCLR" in this solution
The "common language runtime support" setting of "LibCLR"
Target "TestCLR" to ".NET 5.0"
"LibCLR.h" created automatically in project "LibCLR" and codes was inside
#pragma once
using namespace System;
namespace LibCLR {
public ref class Class1
{
// TODO: Add your methods for this class here.
};
}
Add "new LibCLR.Class1();" in MainWindow.xaml.cs in project "TestCLR"
using System.Windows;
namespace TestCLR {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
new LibCLR.Class1();
}
}
}
Rebuild All and debug, then i met exception
Then i change the solution platform to x64 or x84, the exception were the same.
It works well if i choice "WPF App (.NET Framework)" for "TestCLR" in step 1 and "CLR Class Library(.NET Framework)" for "LibCLR" in step 2
Why did not it work?
Can not i use a "CLR Class Library(.NET)" project as a project reference in a "WPF App (.NET Core)" project?
How can i solve this problem?
You should change Platform target to "X86" here
The most common answer is changing between x86 and x64 targets. In a comment to your original question, here, you mentioned that you tried that and it didn't work for you. So, I have a suggestion. You are building a WPF project, and targeting dotnet 5.0. Dotnet 5.0 is OS-agnostic. WPF is OS-specific. It needs Windows.
Try using an OS-specific Target Framework Moniker. Open the .csproj file of both projects. Try setting both projects to <TargetFramework>net5.0-windows</TargetFramework>
Clean solution, rebuild, and test.
We've got a solution here that is dependent on Windows. We shouldn't have to, but let's try explicitly targeting it. Especially that C++ project.
More reading
NET 5: Merging .NET Core and .NET Standard with New Target Framework Monikers (TFMs)
New templates Targeting .NET 5.0
Cannot compile WPF applications targeting .NET 5

(System.IO.FileNotFoundException) .Net core Web API cannot find child dependency (Dependencies of dependency) when added DLL by "Add Reference"

I am getting System.IO.FileNotFoundException in my .Net Core Web API. So I've set up the below project to demonstrate the problem.
I created a.Net Standard library named DemoLibrary and added QRCoder dependency via NuGet.
Disclaimer: Reason for choosing the QRCoder is that the Web API doesn't use it by default. I don't use it in my project. In fact, I'm getting this exception for EntityFrameworkCore.
I created a new .Net Core Web API DemoWebAPI which has no other dependencies.
Then added the DemoLibrary to DemoWebAPI via Add Reference -> Browse -> DemoLibrary.dll.
This is my solution:
The DemoMethod method in Calculate class just creates the object of QRCodeGenerator.
public class Calculate
{
public static string DemoMethod()
{
QRCodeGenerator qrGenerator = new QRCodeGenerator();
return "";
}
}
And my ValuesController in DemoWebAPI just calls the method:
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "value1", "value2", DemoLibrary.Calculate.DemoMethod() };
}
Now, when I run the DemoWebAPI project I get below exception upon the call to the DemoMethod:
System.IO.FileNotFoundException: 'Could not load file or assembly 'QRCoder, Version=1.3.5.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.'
I understand the fact that I have to copy the QRCoder.dll file somewhere. But I fail to understand where to put it. I've already tried putting it in "bin/debug/netcoreapp2.2" of the DemoWebAPI and "bin/debug/netstandard2.0" of the DemoLibrary.
But I couldn't get it working.
Request: Please post your answer as descriptive as you can because I am new to .Net Core.
Edit:
I am aware of the NuGet servers. I have read topics like hosting a NuGet server in IIS and Azure. The reason behind DLL reference is I want to use my DLLs in two projects one of them is a .net core API and the other is .net framework class library which is compiled by NMAKE. I couldn't find any way to restore NuGet packages in the .MAK files.
It looks like you've merely added the DLL for DemoLibrary to your DemoWebApi project. That's not how you should be adding references. Since these are in the same solution, you should add a project reference. That will fix your issue.
Now, let me explain what's actually going on here. Your DemoLibrary has a dependency on QRCoder. It's a NuGet reference, which means that package will be restored (i.e. downloaded) and included in your DemoLibrary build output. However, it will be included as one or more DLLs along side your DemoLibrary.dll. When you then just reference DemoLibrary.dll, you're missing all these other DLLs that are part of DemoLibrary and thus, things don't work properly.
Now, when it comes to a project reference, things are little more complex. A project reference essentially wraps the referenced project into your other project. You can think of it as sort of a sub project. For all intents and purposes, it's like any dependency of the sub project becomes a dependency of the main project. That means that DemoWebAPI now technically has a NuGet package reference to QRCoder even though there's no explicit package reference in its project file. The dependency comes from your DemoLibary project. As such, with a project reference, all the necessary dependencies will be included, because it's as if the main project included those itself, by way of the sub project.
For what it's worth, you should virtually never include a DLL as a reference directly. That used to be required, but the concept of NuGet packages has all but eliminated the practice. Even if DemoLibrary was not in the same solution as DemoWebAPI (meaning you could no longer do a project reference), the correct way to use it would be to turn DemoLibary into a NuGet package, and then reference it in DemoWebAPI via a package reference, like any other NuGet package. You do not simply add the DLL.

How to Make ASP.Net 5 Reference Normal .Net Class Library that is not in your solution

Earlier I asked this question and got an answer that worked. In order to make your ASP.Net 5 application be able to reference a normal .Net class library that targets the .Net Framework 4.5, you must remove the ' "dnxcore50": { }' reference from your project.json file.
Great. That worked with a simple ClassLibrary project which did nothing.
Now I am trying to do it with more complicated class libraries. Class libraries which reference other NuGet Packages for instance (such as HtmlAgilityPack) and the same technique is not working.
This is very frustrating. I am a little dumbfounded that simply referencing a class library no longer works in the new version of ASP.Net.
One of the "features" that seems to be removed is the ability to reference a compiled DLL for a project that is not in your solution. The "Browse" button is gone from the Add Reference dialog in an ASP.Net 5 project:
Whereas a classic project still has the browse button:
Why? How do I reference a class library that is on my machine, yet I do not want to include in my project?
To reference a DLL on your machine but not in your Solution, you'll need to update the project.json as follows:
{
"frameworks" :
{
"dnx451" :
{
"bin" : { "assembly": "<path to dll>", "pdb": "<path to pdb if needed>" }
}
}
}
Unfortunately, much of the dnx tooling is not yet integrated into VS2015 (the teams are separate, and both are changing too quickly to keep up with each other particularly well), and the Asp.net documentation is still a work in progress.

NHibernate - missing dll's

This call
// this._cfg is an NHibernate Configuration instance
this._sessionFactory = this._cfg.BuildSessionFactory();
Gives me this exception at runtime (NOT at compile time).
Could not load file or assembly 'NHibernate.ByteCode.Castle' or one of its dependencies. The system cannot find the file specified.":"NHibernate.ByteCode.Castle
OK so far. But the thing is, this code is running in a class library project, and I have referenced NHibernate.ByteCode.Castle (along with all the other NHibernate dll's) in that project.
Wierder: I can fix the exception by additionally referencing the NHibernate dll's in the Windows WPF executable project that calls my class library. But the Windows WPF executable contains no code that directly uses NHibernate (as evidenced by: It compiles fine without any NHibernate references). So what's going on? Apparently it's insufficient to reference NHibernate.ByteCode.Castle in the project that actually uses the NHibernate stuff. Anyone know why?
I know this is old, but what I've done to fix the dependency problem is simple:
In my UnitOfWork I added one static method:
private static void bringCastleDamnit()
{
var pf = new NHibernate.ByteCode.Castle.ProxyFactoryFactory();
}
Then, and only then, would MSBuild see that it was needed and copy it to my output directory for my (asp.net and console) apps that references my Data project.
I wouldn't reference the castle byte code factory at all; just ensure it (and all other needed dependancies) are copied to the output directory using a post-build step.