简体   繁体   English

使用C#库中的Akka.Net actor调用F#库会导致TypeInitializationException

[英]Calling F# Library with Akka.Net actors from C# library leads to TypeInitializationException

I have in my test solution 3 projects: 我在我的测试解决方案中有3个项目:

  • f# class library (let's name it F#Lib), f#类库(让我们把它命名为F#Lib),
  • f# console application (let's name it F#Console) and f#console应用程序(让我们将其命名为F#Console)和
  • c# console application (C#Console). c#console应用程序(C#Console)。

In the class library I define an akka.net actor: 在类库中我定义了一个akka.net actor:

namespace Just.Test.Project

open Akka.Actor
open Akka.FSharp
open Akka.Configuration

module Actors =

    let system = System.create "WaveNetSystem" (Configuration.defaultConfig())

    let simple = spawn system "simple" (fun mailbox ->
        let rec loop() = actor {
            let! message = mailbox.Receive()
            printfn "%A" message
            return! loop()
        }
        loop()
    )

type MainClass(msg) = let x = Actors.simple <! msg

If I instantiate the MainClass from f# console application, I get expected result: 如果我从f#console应用程序实例化MainClass ,我得到预期的结果:

[<EntryPoint>]
let main argv = 
    Just.Test.Project.MainClass("bugaga!") |> ignore
    System.Threading.Thread.Sleep(1000)
    0 // return an integer exit code

output: 输出:

"bugaga!!!"

But. 但。 If I do the same from c# console app: 如果我从c#console app做同样的事情:

static void Main(string[] args)
{
    new Just.Test.Project.MainClass("bugaga!");
    System.Threading.Thread.Sleep(1000);
}

I get an exception: 我得到一个例外:

System.TypeInitializationException: The type initializer for '<StartupCode$SampleFSharpAkkaNet>.$Test' threw an exception. ---> System.MissingMethodException: Method not found: 'Akka.Actor.IActorRef  Akka.FSharp.Spawn.spawn(Akka.Actor.IActorRefFactory, System.String, Microsoft.FSharp.Core.FSharpFunc`2<Actor`1<!!0>,Cont`2<!!0,!!1>>)'.
   at <StartupCode$SampleFSharpAkkaNet>.$Test..cctor()
   --- End of inner exception stack trace ---
   at Just.Test.Project.Actors.get_simple()
   at Just.Test.Project.MainClass..ctor() in d:\prj\research\AkkaFSharpTest\SampleFSharpAkkaNet\Test.fs:line 20

How should I interpret this exception? 我该如何解释这个例外? What might be wrong? 可能有什么问题?

UPDATE UPDATE

As already noted in comments and in Tomas Petricek answer, the issue is related to the version mismatch. 正如在评论和Tomas Petricek的回答中已经指出的那样,该问题与版本不匹配有关。 The bindingRedirect does the job and everything starts working. bindingRedirect完成工作,一切都开始工作。 But I still have some misunderstanding. 但我仍然有一些误解。

First. 第一。 The Akka.FSharp references FSharp.Core 4.3.1 . Akka.FSharp引用FSharp.Core 4.3.1

Second. 第二。 The F#Lib and F#Console references FSharp.Core 4.4.0 and C#Console has no references to FSharp.Core at all. F#Lib和F#控制台引用FSharp.Core 4.4.0和C#Console根本没有对FSharp.Core引用。

Third. 第三。 The F#Console works like a charm and if I print loaded assemblies I get: F#控制台就像一个魅力,如果我打印加载的程序集,我得到:

FSharpConsole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
FSharpLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Akka, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null
Akka.FSharp, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null

FsPickler, Version=1.2.21.0, Culture=neutral, PublicKeyToken=null
System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

so, no FSharp.Core 4.3.1.0 loaded and everything is tip-top! 所以,没有FSharp.Core 4.3.1.0加载,一切都是tip-top!

Fourth. 第四。 The C#Console does not work. C#控制台不起作用。 The list of loaded assemblies looks a bit strange: 加载的程序集列表看起来有点奇怪:

CSharpConsole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
FSharpLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

FSharp.Core, Version=4.4.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
FSharp.Core, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a

Akka, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null
Akka.FSharp, Version=1.0.6.16, Culture=neutral, PublicKeyToken=null

It means both FSharp.Core, Version=4.4.0.0 and FSharp.Core, Version=4.3.1.0 are loaded. 这意味着FSharp.Core, Version=4.4.0.0FSharp.Core, Version=4.4.0.0FSharp.Core, Version=4.3.1.0 Why? 为什么? And why it does not happened in F#Console case? 为什么在F#Console案件中没有发生这种情况?

SOLUTION

The problem (as usually )) was in my head. 问题(通常))在我脑海里。

First of all, I never looked into the final F#Console config. 首先,我从未研究过最终的F#Console配置。 The initial app.config is quite simple: 最初的app.config非常简单:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>

but after the build it gets (thanks to AutoGenerateBindingRedirects MSBuild flag ) the required buinding redirects: 但是在构建之后(由于AutoGenerateBindingRedirects MSBuild标志 )得到了所需的buinding重定向:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="FSharp.Core" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.4.0.0" newVersion="4.4.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

The second one. 第二个。 C# compiler was trying to notify me about the problem by writing such messages in the build output: C#编译器试图通过在构建输出中编写这样的消息来通知我这个问题:

No way to resolve conflict between "FSharp.Core, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" and "FSharp.Core, Version=4.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a". 无法解决“FSharp.Core,Version = 4.3.1.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”和“FSharp.Core,Version = 4.3.0.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”之间的冲突。 Choosing "FSharp.Core, Version=4.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" arbitrarily. 任意选择“FSharp.Core,Version = 4.3.1.0,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a”。 Consider app.config remapping of assembly "FSharp.Core, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" from Version "4.3.1.0" [C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\FSharp.NETFramework\\v4.0\\4.3.1.0\\FSharp.Core.dll] to Version "4.4.0.0" [C:\\Program Files (x86)\\Reference Assemblies\\Microsoft\\FSharp.NETFramework\\v4.0\\4.4.0.0\\FSharp.Core.dll] to solve conflict and get rid of warning. 考虑从版本“4.3.1.0”[C:\\ Program Files(x86)\\ Reference Assemblies \\ Microsoft \\ FSharp.NETFramework \\ v4.0 \\的app.config重新映射程序集“FSharp.Core,Culture = neutral,PublicKeyToken = b03f5f7f11d50a3a” 4.3.1.0 \\ FSharp.Core.dll]到版本“4.4.0.0”[C:\\ Program Files(x86)\\ Reference Assemblies \\ Microsoft \\ FSharp.NETFramework \\ v4.0 \\ 4.4.0.0 \\ FSharp.Core.dll]解决冲突,摆脱警告。 C:\\Program Files (x86)\\MSBuild\\14.0\\bin\\Microsoft.Common.CurrentVersion.targets(1820,5): warning MSB3276: Found conflicts between different versions of the same dependent assembly. C:\\ Program Files(x86)\\ MSBuild \\ 14.0 \\ bin \\ Microsoft.Common.CurrentVersion.targets(1820,5):警告MSB3276:发现同一依赖程序集的不同版本之间存在冲突。 Please set the "AutoGenerateBindingRedirects" property to true in the project file. 请在项目文件中将“AutoGenerateBindingRedirects”属性设置为true。 For more information, see http://go.microsoft.com/fwlink/?LinkId=294190 . 有关详细信息,请参阅http://go.microsoft.com/fwlink/?LinkId=294190

But I decided that C# compiler is just a little more restrictive as F# compiler. 但我认为C#编译器只是比F#编译器更具限制性。 I didn't know that in F# projects the flag is set automatically. 我不知道在F#项目中,标志是自动设置的。 What stoped me from checking it? 什么阻止我检查它? I do not know! 我不知道! )

This sounds like an FSharp.Core.dll version mismatch issue. 这听起来像FSharp.Core.dll版本不匹配问题。

Most likely, you are referencing a newer version of FSharp.Core.dll than the one that has been referenced by the F# wrapper library for Akka.net. 最有可能的是,您引用的是较新版本的FSharp.Core.dll不是由Akka.net的F#包装器库引用的版本。 You can either reference the same version, or add a config file with bindingRedirect . 您可以引用相同的版本,也可以使用bindingRedirect添加配置文件。 See Mark Seemann's blog post . 请参阅Mark Seemann的博客文章

The keyword here is MethodMissingException - you are getting that because the signature of the method involves types from FSharp.Core.dll and the version that has been loaded (based on the reference in the C# project) does not match the version exposed by the wrapper (based on the reference used when compiling the wrapper). 这里的关键字是MethodMissingException - 你得到的是因为方法的签名涉及来自FSharp.Core.dll类型,并且已加载的版本(基于C#项目中的引用)与包装器公开的版本不匹配(基于编译包装器时使用的引用)。 Because of the version mismatch, the types are treated as different and "method is not found". 由于版本不匹配,类型被视为不同,并且“找不到方法”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM