asp.net-core-signalr

Difference between SendAsync and SendCoreAsync methods in SignalR Core?


When updating to the latest version of ASP Net Core and SignalR core, I noticed there are two "send" methods available when sending methods to a client (what used to be InvokeAsync).

After looking at the code comments, both methods are identical in comments, both inherit from IClientProxy, and both accept a string method, object args and then a cancellation token.

What are the differences in these methods? If any? and which should be used when?


Solution

  • Quoting @anurse from GitHub:

    Long story short:

    The Core methods should be ignored unless you really know what you're doing.

    Short story long:

    We started with SendAsync, which takes an array of arguments to send:

    public void SendAsync(string method, object[] args);
    
    Clients.All.SendAsync("Method", new object[] { arg1, arg2, arg3 });
    

    Obviously it's a pain to have to create an array every time. The easy fix for that would be to use params:

    public void SendAsync(string method, params object[] args);
    
    Clients.All.SendAsync("Method", arg1, arg2, arg3);
    

    However, that falls apart when you actually want to send an array as a single argument

    public void SendAsync(string method, params object[] args);
    
    var arg1 = new object[] { a, b, c };
    
    Clients.All.SendAsync("Method", arg1);
    
    // C# 'params' expands this into the below
    
    Clients.All.SendAsync("Method", a, b, c);
    

    So instead of sending a single argument that is an array a, b, c, we've sent each of those as separate arguments. This was confusing users.

    So we removed the params from it and instead we generate a whole bunch of extension methods that support multiple arguments:

    public void SendAsync(string method, object[] args);
    public void SendAsync(string method, object arg1) => SendAsync(method, new object[] { arg1 });
    public void SendAsync(string method, object arg1, object arg2) => SendAsync(method, new object[] { arg1, arg2 });
    // ... etc ...
    

    But there's still ambiguity when you have code like this:

    public void SendAsync(string method, object[] args);
    public void SendAsync(string method, object arg1) => SendAsync(method, new object[] { arg1 });
    
    var arg = new object[] { a, b, c }
    
    Clients.All.SendAsync("method", arg);
    

    Again, the overload that takes an object[] will be chosen (…)

    So, we renamed the one that takes an array to SendCoreAsync:

    public void SendCoreAsync(string method, object[] args);
    public void SendAsync(string method, object arg1) => SendCoreAsync(method, new object[] { arg1 });
    
    var arg = new object[] { a, b, c }
    
    // No ambiguity here!
    Clients.All.SendAsync("method", arg);