3

What is the best way to send a list of different objects via SignalR to the clients?

When i use a list of objects with the same base, the client only receive properties of the base class:

class Update { }
class UpdateA { public string PropertyA {get; set;}}
class UpdateB { public string PropertyB {get; set;}}
...
IEnumerable<Update> updates = GetUpdates();
await Clients.Caller.SendAsync("update", updates);

When I use pre serialized data in form of strings, the serialzier escapte the json data as strings.

IEnumerable<string> updates = GetUpdates();
await Clients.Caller.SendAsync("update", updates);
// data looks like: [ "{...}", "{...}" ]

Do I have to write my own serialzier? How does it work for SignalR in dotnet core?

1
  • 1
    Why not directly use a complex class and inlcude all the objects , and at last send to clients? Commented Feb 11, 2020 at 7:38

2 Answers 2

8

I know this is an old question but here is an other solution that does not requires to write your own CustomConverter and relies on the NewtonSoft solution instead:

  1. First you need to install this package: Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson

  2. On the server side, you need to add the following calls in you Startup.cs class:

    services.AddSignalR()
        .AddNewtonsoftJsonProtocol(opts => 
            opts.PayloadSerializerSettings.TypeNameHandling = TypeNameHandling.Auto);
    
  3. if your client is a C# client, you have to add the same configuration when building the connection:

    new HubConnectionBuilder()
        .WithUrl("/yourhub")
        .AddNewtonsoftJsonProtocol(opts => 
            opts.PayloadSerializerSettings.TypeNameHandling = TypeNameHandling.Auto)
        .Build();
    

If your client is not a C# client, I guess you will have to manage the deserialization yourself. NewtonSoft.Json just adds a $type property to the generated JSON containing the fully qualified type name (for example: Your.Namespace.ClassName) so you can use it to select the according type to deserialize with.

source: MSDN

Sign up to request clarification or add additional context in comments.

2 Comments

after trying so many things finally its working. Thank you
This was really helpful. Thank you
2

send a list of different objects with the same base via SignalR to the clients

You can try to achieve the requirement by creating and using a custom converter, like below.

In custom converter MyConverterWithTypeDiscriminator

public override void Write(Utf8JsonWriter writer, Update value, JsonSerializerOptions options)
{
    writer.WriteStartObject();

    if (value is UpdateA updateA)
    {
        writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.UpdateA);
        writer.WriteString("PropertyA", updateA.PropertyA);
    }
    else if (value is UpdateB updateB)
    {
        writer.WriteNumber("TypeDiscriminator", (int)TypeDiscriminator.UpdateB);
        writer.WriteString("PropertyB", updateB.PropertyB);
    }

    writer.WriteString("UpdatedAt", value.UpdatedAt);

    writer.WriteEndObject();
}

Base class and derived classes

public class Update
{
    public DateTime UpdatedAt { get; set; }
}

public class UpdateA : Update
{
    public string PropertyA { get; set; }
}

public class UpdateB : Update
{
    public string PropertyB { get; set; }
}

In Startup.cs

services.AddSignalR().AddJsonProtocol(options => options.PayloadSerializerOptions.Converters.Add(new MyConverterWithTypeDiscriminator()));

In Hub method

var updates = new List<Update>
{
    new UpdateA
    {
        UpdatedAt=DateTime.Now.AddDays(-1),
        PropertyA = "A"
    },
    new UpdateB
    {
        UpdatedAt=DateTime.Now.AddDays(-1),
        PropertyB = "B"
    }
};

await Clients.All.SendAsync("ReceiveUpdate", updates);

Test Result

enter image description here

Note: to implement your custom converter, please check this link: https://learn.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-converters-how-to#support-polymorphic-deserialization

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.