Akka - 无法在 F# 中将受歧视的联合作为消息发送

Akka - Unable to send Discriminated Unions as messages in F#

Akka - 区分联合作为 F# 中的消息

我无法使用受歧视的工会作为消息给 akka 演员。如果有人能指出一个这样做的例子,我将不胜感激。

我自己的尝试是在 git@github.com:Tweega/AkkaMessageIssue.git。 (下面的片段)。它是在 https://github.com/rikace/AkkaActorModel.git(聊天项目)

中找到的示例的简化版本

问题

DU 消息从未在服务器 actor 上找到它的目标,而是被发送到死信箱。相反,如果我发送对象,它们确实会到达。

如果我发送一个 DU,但将我的服务器 actor 设置为侦听通用对象,消息确实会到达,但它的类型是

    seq [seq [seq []]

我无法了解底层 DU。

我正尝试作为消息发送的 DU

    type PrinterJob =
    | PrintThis of string
    | Teardown 

客户端代码

    let system = System.create "MyClient" config

   let chatClientActor =
       spawn system "ChatClient" <| fun mailbox ->
           let server = mailbox.Context.ActorSelection("akka.tcp://MyServer@localhost:8081/user/ChatServer")

           let rec loop nick = actor {
               let! (msg:PrinterJob) = mailbox.Receive()
               server.Tell(msg)
               return! loop nick
               }
           loop ""

   while true do
       let input = Console.ReadLine()        
       chatClientActor.Tell(PrintThis(input))

消息从控制台输入转发到客户端

    while true do
        let input = Console.ReadLine()     
        chatClientActor.Tell(PrintThis(input))

服务器代码

    let system = System.create "MyServer" config
    let chatServerActor =
        spawn system "ChatServer" <| fun (mailbox:Actor<_>) ->
            let rec loop (clients:Akka.Actor.IActorRef list) = actor {
                let! (msg:PrinterJob) = mailbox.Receive()

                printfn "Received %A" msg   //Received seq [seq [seq []]; seq [seq [seq []]]]  ???

                match msg with                
                    | PrintThis str -> 
                        Console.WriteLine("Printing: {0} Do we get this?", str)
                        return! loop clients
                    | Teardown -> 
                        Console.WriteLine("Tearing down now")                        
                        return! loop clients                
            }
    loop []

依赖项

(我在这里没有使用 paket)- 下面的 PM 命令:

我在 net5.0 中托管应用程序

构造函数参数名称 - 奇怪?

当作为对象传入class实例时,akka似乎对构造函数参数的名称很敏感。消息得到处理,但数据没有从客户端复制到服务器。如果你有一个叫Username的属性,构造函数参数不能是,比如uName,否则到达服务器时它的值为null。代码在分支参数中。

type DoesWork(montelimar: string) =
    member x.Montelimar = montelimar
    
type DoesNotWork(montelimaro: string) =
    member x.Montelimar = montelimaro

我在 Akka.NET 存储库中打开了一个问题:https://github.com/akkadotnet/akka.net/issues/5194

并为此添加了详细的复制:https://github.com/akkadotnet/akka.net/pull/5196

但看起来 Newtonsoft.Json 在没有给出类型提示的情况下确实无法执行此反序列化,Akka.NET 的网络序列化默认情况下不会为 JSON 执行此反序列化:

type TestUnion = 
  | A of string
  | B of int * string

type TestUnion2 = 
  | C of string * TestUnion
  | D of int
  

[<Fact(Skip="JSON.NET really does not support even basic DU serialization")>]
member _.``JSON.NET must serialize DUs`` () =
    let du = C("a-11", B(11, "a-12"))
    let settings = new JsonSerializerSettings()
    settings.Converters.Add(new DiscriminatedUnionConverter())
    
    let serialized = JsonConvert.SerializeObject(du, settings)
    let deserialized = JsonConvert.DeserializeObject(serialized, settings)
    
    Assert.Equal(du :> obj, deserialized)

该测试不会通过,它根本不使用任何 Akka.NET 的基础结构 - 因此默认的 JSON 序列化程序根本不适用于真实世界的 F# 用例.

我们可以尝试更改序列化系统的默认设置以包含类型提示,但这需要进行大量验证测试(对于没有序列化的旧 Akka.Persistence 数据)。

一个更好的解决方案,我的拉请求验证,是使用 Hyperion 进行多态序列化 - 它对您来说同样透明,但它对复杂类型的处理比 Newtonsoft.Json 更强大,实际上是更快:https://getakka.net/articles/networking/serialization.html#how-to-setup-hyperion-as-default-serializer