SignalR not serializing/deserializing custom DataMember name

Viewed 2463

I am working on a project and trying to integrate SignalR into it. I have a class with a data contract which allows me to use an underscore separated format on my client, and standard Pascal Case on the server, something like this:

[DataContract]
public class Foo {

    [DataMember(Name = "first_name")]
    FirstName { get;set; }

    [DataMember(Name = "last_name")]
    LastName { get;set; }

    [DataMember(Name = "phone")]
    Phone { get;set; }
}

This works fine when passing data through a fetch command to the Razor Page OnGet and OnPost methods, but does not work when using SignalR.

When sending data to server via SignalR, first_name and last_name are null, while phone gets sent correctly.

How can I make SignalR respect the DataMember Name when serializing/deserializing?

3 Answers

I was able to resolve this issue by using the Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson package and adding the following in Startup.cs

services.AddSignalR()
        .AddNewtonsoftJsonProtocol();

I suppose currently you are sending the data as an object, somehow like this:

Foo foo = new Foo();
_hub.Clients.All.InvokeAsync("ReceiveMessage", foo);

What I suggest is that you create the JSON by hand on the server side and send that, because you have better controll over the property names that way.

Add the JsonProperty attribute to the Foo class:

[DataContract]
public class Foo {

    [DataMember(Name = "first_name")]
    [JsonProperty("first_name")]
    FirstName { get;set; }

    [DataMember(Name = "last_name")]
    [JsonProperty("last_name")]
    LastName { get;set; }

    [DataMember(Name = "phone")]
    [JsonProperty("phone")]
    Phone { get;set; }
}

And when you send the message, send the JSON string instead of letting SinglaR parse your object:

Foo foo = new Foo();
string json = JsonConvert.SerializeObject(foo);
_hub.Clients.All.InvokeAsync("ReceiveMessage", json);

The fields are not being serialized because their serialization attributes ([DataMember]) are not compatible with SignalR's default serialization engine (System.Text.Json).

One possible solution is to switch the serialization engine to Newtonsoft's JSON implementation, as suggested in @Aleksandr Albert's answer. Another solution is to use System.Text.Json.Serialization.JsonIncludeAttribute instead, e.g.

public class Foo {
    [JsonPropertyName("first_name")]
    [JsonInclude]
    FirstName { get;set; }

    [JsonPropertyName("last_name")]
    [JsonInclude]
    LastName { get;set; }

    [JsonPropertyName("phone")]
    [JsonInclude]
    Phone { get;set; }
}

Each solution is (in)compatible with one of the serialization engines.

Related