We have to use api from 3rd party vendor(perforce). Till today, we were able to reference and use that API in .net framework application. But, now we are refactoring our product and of course we decided to use new .net environment, which is .net core 2.2. As, Perforce didn't publish that library for .net core, we decided to port that library to .net standard.
So, in a nutshell we downloaded source code, ported, and added as a reference in .net core project.
So far, so good. A weird thing is that, after some usage of that library we are getting ExecutionEngineException
from that library, which triggers Environment.Failfast
and terminates application.
One more important information is that library uses another native library(p4bridge.dll).
The exception is so:
FailFast:
A callback was made on a garbage collected delegate of type 'p4netapi!Perforce.P4.P4CallBacks+LogMessageDelegate::Invoke'.
at Perforce.P4.P4Bridge.RunCommandW(IntPtr, System.String, UInt32, Boolean, IntPtr[], Int32)
at Perforce.P4.P4Bridge.RunCommandW(IntPtr, System.String, UInt32, Boolean, IntPtr[], Int32)
at Perforce.P4.P4Server.RunCommand(System.String, UInt32, Boolean, System.String[], Int32)
at Perforce.P4.P4Command.RunInt(Perforce.P4.StringList)
at Perforce.P4.P4CommandResult..ctor(Perforce.P4.P4Command, Perforce.P4.StringList)
at Perforce.P4.P4Command.Run(Perforce.P4.StringList)
at Perforce.P4.Client.runFileListCmd(System.String, Perforce.P4.Options, System.String, Perforce.P4.FileSpec[])
at Perforce.P4.Client.SyncFiles(System.Collections.Generic.IList`1<Perforce.P4.FileSpec>, Perforce.P4.Options)
I am already aware of the message related to garbage collected delegate
. It seems, at some place pointer to the delegate is passed to unmanaged library and then GC collected it.
We take a look to the source code of that api. And we saw some possible places which can be reason for that error. But, this is just a thought.
While investigating the failure, we created another .net framework application which references to that ported library, and then we didn't came across any error in .net framework.
My questions are:
NET Core supports the . NET Standard Library, which allows your library to be called by any . NET platform that supports that version of the . NET Standard Library.
NET Framework, Mono, Xamarin or Unity has to implement - at minimum - to support that version of the Standard. For library authors targeting . NET Standard provides the same feature set across all supported platforms - if it compiles to . NET Standard it'll very likely run on those frameworks.
. Net Core does not support desktop application development and it rather focuses on the web, windows mobile, and windows store. . Net Framework is used for the development of both desktop and web applications as well as it supports windows forms and WPF applications.
You cannot consume a . Net Standard 2.1 assembly in any . Net Framework Version because the . NET Framework (even the last ever version, 4.8) does not implement .
Thank you. Several technologies available to .NET Framework libraries aren't available for use with .NET 5+ (and .NET Core), such as app domains, remoting, and code access security (CAS). If your libraries rely on one or more of the technologies listed on this page, consider the alternative approaches mentioned.
Because .NET Core 2.0 implements .NET Standard 2.0, it also has the compatibility mode for referencing .NET Framework libraries. However, not all .NET Framework libraries will work on all .NET implementations. For example, they might use Windows Forms or WPF APIs.
However, many of the general-purpose libraries only target .NET Framework because they were created when .NET Standard simply didn’t exist yet. With .NET Standard 2.0, the API set is large enough so that most, if not all, of the general-purpose libraries can target .NET Standard.
If you want to build a Apps that will support .NET framework V4.5, Windows, iOS, Android, Linux, Mono and UWP then you should go for .NET standard version 1.0.
I thought to post answer to my question as I already solved the issue. And as you are reading my answer now it means that you have faced with a similar problem. First of all, I want to thank to @MarcGravell for his comments and recommend to you to read the comments.
At first, want to summarize answer to the 2nd question:
How is that possible that, .net framework and .net core reacts to the same library in a different ways?
To be honest, from the first glance I was thinking that .net standard library will behave itself in a same manner everywhere. But, of course I was wrong.
Let's start by "defintion" of .Net Standard
. .NET Standard
is nothing but a specification (think of it as an Interface), it just only declares what types and APIs are exposed by a specific platform depending on is version.
If you will take a look, you will see that your standard library references the .NET Standard SDK that contains a netstandard.dll
containing the APIs or, to better say, the contract, we can use from within the library project. If you will take a look, to the your standard library with Ildasm.exe
, you will see that it is using .netstandard.dll
.
And let's check how it is used by our core and framework apps. And in core it works better than framework.
I am always a fan of diagrams:
As you see in the diagram, both core and framework apps reference their own netstandard.dll
. And those libraries are built based on the type forwarding
concept.
For core apps, BCL
types are provided by System.Runtime.dll
, while in case of framework apps BCL
types are provided by mscorlib.dll
. So, two different implementations.
For example, here is the IL code of .netstandard
library which will be used by core apps:
Read more about type forwarding from msdn.
Source of details about .NET Standard
.
And now a bit regarding to my first question:
Is there any difference between .net framework and .net core in terms of garbage collector mechanism?
Actually it must not be surprise that Microsoft continues to evolve GC mechanism.
And now how I solved the issue:
Good thing was that library which I ported to standard was open source. I investigated the issue, and in a nutshell they are passing delegate pointer to the unmanaged library. And that unmanaged library saves the pointer and tries to use it during some lifetime which is longer that the lifetime of that pointer. Actually, the interesting point is that framework GC is not collecting that delegate somehow and that's why no exception in framework side. But, in case of core GC collects that delegate and creates reason to the failure. I did change the way how I set that field and it works now. I declared that field as static and initialize it inside static constructor, so lifetime of that delegate is as long as app lifetime.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With