.net标准库在.net核心中失败,但在框架中未失败 - c#

我们必须使用第三方供应商(perforce)的api。到今天为止,我们已经能够在.net框架应用程序中引用和使用该API。但是,现在我们正在重构产品,我们当然决定使用新的.net环境,即.net core 2.2。由于Perforce并未针对.net核心发布该库,因此我们决定将该库移植到.net标准。

因此,简而言之,我们下载了源代码,进行了移植,并添加为.net核心项目中的参考。

到目前为止,一切都很好。奇怪的是,在对该库进行了一些使用之后,我们从该库中获取了ExecutionEngineException,这会触发Environment.Failfast并终止应用程序。

一个更重要的信息是该库使用另一个本机库(p4bridge.dll)。

例外是:

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)

我已经知道与garbage collected delegate有关的消息。似乎在某个地方,将指向该委托的指针传递给非托管库,然后GC对其进行收集。

我们来看一下该api的源代码。我们看到了一些可能的地方,这可能是导致该错误的原因。但是,这只是一个想法。

在调查故障时,我们创建了另一个.net框架应用程序,该应用程序引用了该移植的库,然后在.net框架中没有遇到任何错误。

我的问题是:

在垃圾收集器机制方面,.net框架和.net核心之间有什么区别吗?
.net框架和.net核心如何以不同的方式对同一个库做出反应?

参考方案

我已经解决了这个问题,因此想发布对我问题的答案。当您现在阅读我的答案时,这意味着您遇到了类似的问题。首先,我要感谢@MarcGravell的评论,并建议您阅读这些评论。

首先,要总结对第二个问题的答案:

.net框架和.net核心如何对
同一图书馆以不同的方式?

坦白地说,乍一看,我一直认为.net标准库在任何地方都将以相同的方式表现。但是,我当然错了。

让我们从.Net Standard的“定义”开始。 .NET Standard只是一个规范(将其视为接口),它仅声明特定平台根据版本公开哪些类型和API。

如果您看一看,您会看到您的标准库引用了.NET Standard SDK,该SDK包含一个包含API或的netstandard.dll,我们可以在库项目中使用它。如果您看一下使用Ildasm.exe的标准库,将会看到它正在使用.netstandard.dll

.net标准库在.net核心中失败,但在框架中未失败 - c#

让我们检查一下我们的核心和框架应用程序如何使用它。从根本上说,它比框架更好地工作。

我一直是图表的拥护者:

.net标准库在.net核心中失败,但在框架中未失败 - c#

如您在图中所看到的,核心和框架应用程序都引用了它们自己的netstandard.dll。这些库是基于type forwarding概念构建的。
对于核心应用程序,BCL类型由System.Runtime.dll提供,而对于框架应用程序,BCL类型由mscorlib.dll提供。因此,有两种不同的实现。

例如,下面是核心应用将使用的.netstandard库的IL代码:

.net标准库在.net核心中失败,但在框架中未失败 - c#

阅读有关type forwarding from msdn的更多信息。

Source有关.NET Standard的详细信息。

现在,关于我的第一个问题:

.net框架和.net核心之间在术语上是否有任何区别
收集器机制?

实际上,Microsoft不断发展GC机制也就不足为奇了。

现在,我如何解决该问题:

好东西是我移植到标准库是开源的。我调查了这个问题,并且简而言之,他们正在将委托指针传递给非托管库。并且该非托管库将保存指针,并尝试在某个生命周期内使用该指针,该生命周期比该指针的生命周期更长。实际上,有趣的一点是,框架GC不会以某种方式收集该委托,这就是为什么框架方面没有例外的原因。但是,在核心GC的情况下,收集该委托并为失败创建原因。我确实更改了设置该字段的方式,现在它可以正常工作。我将该字段声明为static并在static构造函数中对其进行初始化,因此该委托的生命周期与应用程序生命周期一样长。

java.net.URI.create异常 - java

java.net.URI.create("http://adserver.adtech.de/adlink|3.0") 抛出java.net.URISyntaxException: Illegal character in path at index 32: http://adserver.adtech.de/adlink|3.0 虽然n…

在ASP.NET WebForms中在服务器端初始化bootsrap datatimepicker - javascript

我有这个HTML<div class='datepicker input-group date' id='datetimepickerStart'> <input type='text' class="form-control" /> <span c…

SQLite。修复sqlite-net-wp8项目依赖项 - c#

为什么SQLGet在NuGet上不可用?为什么它是Visual Studio的一部分,您必须在“工具”->“扩展和更新”中查找更新?在过去的几个月中,我开始对Windows 8和Windows Phone 8进行编码,我希望对此有所了解。对我来说,在Windows 8项目上使用SQLite会创建VS级依赖关系。假设我使用Visual Studio ID…

C#如何将System.Net.ConnectStream转换为字节[](数组) - c#

我试图将流(System.Net.ConnectStream)转换为字节数组。关于如何做到这一点的任何想法/例子? 参考方案 Stream sourceStream = ... // the ConnectStream byte[] array; using (var ms = new MemoryStream()) { sourceStream.CopyT…

使用Javascript在ASP.NET MVC控制器操作上通过POST下载文件(HttpPost操作) - c#

最初,我的控制器操作接受GET。当我的数据增长时,我被迫转向POST方法,以便能够发送更大的数据。我的控制器动作如下:[HttpPost] public ActionResult ClausesPdf(MyArrayModel obj) { ... return File(pdf, "application/pdf", "fil…