2016-04-06 10 views
3

ich in meinem Testlösung 3 Projekte müssen TypeInitializationException:Aufruf F # Bibliothek mit Akka.Net Akteure aus C# Bibliothek führt

  • f # Klassenbibliothek (seien wir F # Lib nennen),
  • f # -Konsolenanwendung (nennen wir es F # Console) und
  • C# Konsolenanwendung (C# -Konsole).

In der Klassenbibliothek ich einen akka.net Schauspieler definieren:

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 

Wenn ich die MainClass von f # Konsolenanwendung instanziiert, bekomme ich erwartetes Ergebnis:

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

Ausgabe:

"bugaga!!!" 

Aber. Wenn ich das gleiche von C# Konsolenanwendung tun:

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

Ich erhalte eine Ausnahme:

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 

Wie soll ich diese Ausnahme zu interpretieren? Was könnte falsch sein?

UPDATE

Wie bereits in den Kommentaren und in Tomas Petricek Antwort erwähnt, ist das Problem auf die Versionskonflikt zusammen. Die bindingRedirect erledigt den Job und alles fängt an zu arbeiten. Aber ich habe immer noch ein Missverständnis.

Zuerst. Die Akka.FSharp Referenzen FSharp.Core 4.3.1.

Sekunde. Die F # Lib- und F # -Konsolenreferenzen FSharp.Core 4.4.0 und C# Console haben überhaupt keine Referenzen auf FSharp.Core.

Dritte. Die F # Konsole funktioniert wie ein Charme, und wenn ich geladen Baugruppen drucke ich bekommen:

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, keine FSharp.Core 4.3.1.0 geladen und alles ist tip-top!

Vierte. Die C# -Konsole funktioniert nicht. Die Liste der geladenen Baugruppen sieht ein bisschen seltsam:

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 

Es bedeutet sowohl FSharp.Core, Version=4.4.0.0 und FSharp.Core, Version=4.3.1.0 geladen. Warum? Und warum ist es nicht in F # Console Fall passiert?

SOLUTION

Das Problem (wie sonst üblich)) war in meinem Kopf.

Zunächst einmal habe ich nie in die endgültige F # Console Config geschaut.Die anfängliche app.config ist ganz einfach:

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

aber nach dem Build wird es (dank AutoGenerateBindingRedirects MSBuild flag) die erforderliche buinding umleitet:

<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> 

die zweite. C# Compiler versucht, mich über das Problem zu informieren, indem solche Nachrichten in der Build-Ausgabe schreiben:

Keine Möglichkeit zur Beilegung von Konflikten zwischen "FSharp.Core, Version = 4.3.1.0, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a" und "FSharp.Core, Version = 4.3.0.0, Kultur = neutral, PublicKeyToken = b03f5f7f11d50a3a". Wählen Sie "FSharp.Core, Version = 4.3.1.0, Kultur = neutral, PublicKeyToken = b03f5f7f11d50a3a" beliebig. Betrachten Sie das App.config-Remapping der Assembly "FSharp.Core, Culture = neutral, PublicKeyToken = b03f5f7f11d50a3a" aus Version "4.3.1.0" [C: \ Programme (x86) \ Reference Assemblies \ Microsoft \ FSharp.NETFramework \ v4.0 \ 4.3.1.0 \ FSharp.Core.dll] bis Version "4.4.0.0" [C: \ Programme (x86) \ Referenz-Assemblys \ Microsoft \ FSharp.NETFramework \ v4.0 \ 4.4.0.0 \ FSharp.Core.dll ] Konflikt zu lösen und Warnung loszuwerden. C: \ Programme (x86) \ MSBuild \ 14.0 \ bin \ Microsoft.Common.CurrentVersion.targets (1820,5): Warnung MSB3276: Konflikte zwischen verschiedenen Versionen derselben abhängigen Assembly gefunden. Setzen Sie die Eigenschaft "AutoGenerateBindingRedirects" in der Projektdatei auf "true". Weitere Informationen finden Sie unter http://go.microsoft.com/fwlink/?LinkId=294190.

Aber ich entschied, dass C# -Compiler nur ein wenig restriktiver als F # -Compiler ist. Ich wusste nicht, dass in F # -Projekten die Flagge automatisch gesetzt wird. Was hat mich davon abgehalten, es zu überprüfen? Ich weiß es nicht!)

+0

Sie haben verschiedene Versionen einiger Bibliotheken, auf die in verschiedenen Projekten verwiesen wird. –

+0

Ausnahmebedingungen besagt, dass die Spawn-Methode in C# App nicht erkannt wurde. Verfügen Sie über Akka.FSharp- und FSharp.Core-Assemblys, auf die in Ihrem C# -Projekt verwiesen wird? – Horusiath

+0

@horusiath Es ist, was ich auch dachte, aber nein, alles sieht hier korrekt aus. –

Antwort

3

Dies klingt wie ein FSharp.Core.dll Version Mismatch-Problem.

Höchstwahrscheinlich verweisen Sie auf eine neuere Version von FSharp.Core.dll als die, die von der F # -Wrapper-Bibliothek für Akka.net referenziert wurde. Sie können entweder auf dieselbe Version verweisen oder eine Konfigurationsdatei mit bindingRedirect hinzufügen. Siehe Mark Seemann's blog post. Das Schlüsselwort hier lautet MethodMissingException - Sie erhalten das, weil die Signatur der Methode Typen von FSharp.Core.dll enthält und die Version, die geladen wurde (basierend auf der Referenz im C# -Projekt) nicht mit der vom Wrapper bereitgestellten Version übereinstimmt (basierend auf der Referenz, die beim Kompilieren des Wrappers verwendet wurde). Aufgrund der Versionskonflikte werden die Typen als unterschiedlich behandelt und "Methode wird nicht gefunden".

+0

Sie haben recht, das 'bindingRedirect' hilft sehr. Habe aber immer noch keine Ahnung, warum es sich von der F # Version unterscheidet. Ich habe meinen Beitrag aktualisiert. Könnten Sie bitte einen Blick darauf werfen? –

+0

Erstellt das F # -Projekt nicht automatisch die Konfigurationsdatei mit verbindlichen Weiterleitungen? Ich denke, es gibt einige MSBuild-Option, um das zu tun ... –

+0

Ahhh ,,,,, Wirklich! Ich war mir der MSBuild-Option nicht bewusst und schaute nie in die endgültige Konfiguration. In der initialen app.config gab es natürlich keine verbindlichen Weiterleitungen. –