Search code examples
c#signalr

SignalR SendAsync list of objects calls ToString rather than using my jsonserializer?


I am trying to send a list of objects to my signalr clients, but the framework seems to ignore the json serializer and uses the ToString method instead. This only happens if it's a List<object>, it can handle a regular object just fine.

A somewhat contrived simplified example:

public abstract class Animal {}
public class Dog : Animal {
    public bool GoodBoy { get; set; }
    public override string ToString() {
        return "hello from dog";
    }
}
public class Cat : Animal {
    public bool Hungry { get; set; } // only cats can be hungry, dont think too much about it
}

// ... class MyHub : Hub { ...

// Input is: type = typeof(Dog) and animals is a list of 1 dog
public void SendChanges(Type type, List<Animal> animals) {
    // Just serializing the animals without casting them gives incorrect objects
    Console.WriteLine(JsonSerializer.Serialize(animals)); // Prints [{}]

    // So we have to cast to the input type
    var animalsAsType = animals.Select(a => Convert.ChangeType(a, type).ToList();
    Console.WriteLine(JsonSerializer.Serialize(animalsAsType)); // Prints [{"GoodBoy":true}]

    // However, ...
    Clients.Others.SendAsync($"On{type.Name}Changed", animalsAsType); // Clients receive ["hello from dog"]
}

What am I doing wrong here? I suspect there's something wrong in my linq Select, but I am unsure how to cast an Animal to type (with it throwing a ClassCastException if the animal instance is not actually the type we're trying to cast to) that does not use Convert.ChangeType.

Note: Due to technical limitations in my real code I do require that the signature of SendChanges(Type type, List<Animal> animals) doesn't change.


Solution

  • I found the issue: Turns out that I forgot that I had registered a custom json converter that used ToString. Once I followed this solution everything worked perfectly.