Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consolidate multiple SendAsync overloads with a params object?[] approach #59704

Closed
ilkerkeklik01 opened this issue Jan 3, 2025 · 2 comments
Closed
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-signalr Includes: SignalR clients and servers

Comments

@ilkerkeklik01
Copy link

Background and Motivation

ASP.NET Core’s ClientProxyExtensions currently offers numerous SendAsync overloads for varying argument counts (from 0 to 10). Each overload simply allocates a fixed-size object[] and calls SendCoreAsync.

While this design provides explicit discoverability (i.e., IntelliSense will show an overload for every possible argument count), it also comes with:

  • A large API surface and repetitive signatures.

  • Complexity in maintenance (any future additions potentially require more overloads).

  • Potential confusion for new contributors or library users due to the large number of nearly identical methods.

Goal: Consolidate these multiple overloads into a smaller API surface by using params object?[] parameters, which can handle an arbitrary number of arguments.

Proposed API

Below is a diff of the suggested API changes in a ref-assembly-style format. The main idea is to introduce one (or two) SendAsync method(s) with a params parameter, and potentially retire or mark obsolete the existing overloads.

namespace Microsoft.AspNetCore.SignalR
{
    public static class ClientProxyExtensions
    {
+       // 1) Overload without CancellationToken
+       public static Task SendAsync(
+           this IClientProxy clientProxy,
+           string method,
+           params object?[] args
+       );

+       // 2) Overload with CancellationToken
+       public static Task SendAsync(
+           this IClientProxy clientProxy,
+           string method,
+           CancellationToken cancellationToken,
+           params object?[] args
+       );

        // Existing overloads might be marked as obsolete or removed
        // depending on the final approach for backward compatibility.
    }
}

Usage Examples

Consider how calling code might look if we adopt this design:

// Old style (with explicit overloads):
await Clients.Caller.SendAsync("MethodName");
await Clients.Caller.SendAsync("MethodName", arg1);
await Clients.Caller.SendAsync("MethodName", arg1, arg2);
await Clients.Caller.SendAsync("MethodName", arg1, arg2, arg3, token);

// New style (with a params array):
await Clients.Caller.SendAsync("MethodName");                      // zero args
await Clients.Caller.SendAsync("MethodName", arg1);               // one arg
await Clients.Caller.SendAsync("MethodName", arg1, arg2);         // two args
await Clients.Caller.SendAsync("MethodName", cancellationToken, arg1, arg2, arg3);

Developers can pass any number of arguments without needing a dedicated overload.

Alternative Designs

  1. Mark existing overloads as [Obsolete] and provide a grace period before removal:
  • Pros: A safe migration path; developers aren’t forced to switch overnight.
  • Cons: Slightly more complex code until they are formally removed in a future major version.
  1. Remove existing overloads outright (breaking change):
  • Pros: Cleanest final API surface.
  • Cons: A direct breaking change for all codebases that reference the old methods.

Risks

  1. Backward Compatibility / Breaking Change:
  • Existing code using the old overloads will need to be recompiled or updated.
  • Some usage patterns might experience ambiguous resolution if using parameters that match the new params method signatures in a particular way.
  1. Discoverability:
  • Developers might not realize they can pass multiple arguments via params.
  • IntelliSense no longer shows a convenient list of overloads by argument count.
  1. Documentation & Samples:
  • Tutorials, blog posts, and official docs referencing SendAsync overloads might need to be updated.
@ilkerkeklik01 ilkerkeklik01 added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label Jan 3, 2025
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically label Jan 3, 2025
@mkArtakMSFT mkArtakMSFT added area-signalr Includes: SignalR clients and servers and removed needs-area-label Used by the dotnet-issue-labeler to label those issues which couldn't be triaged automatically labels Jan 3, 2025
@BrennanConroy
Copy link
Member

Here is a good explanation of why we did it this way instead of using params:
aspnet/SignalR#2239 (comment)

I don't see much benefit in us changing this especially with the risk of a breaking change/backwards compat. We've seen no complaints in the past 6+ years about this.

@ilkerkeklik01
Copy link
Author

Thanks for the explanation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-signalr Includes: SignalR clients and servers
Projects
None yet
Development

No branches or pull requests

3 participants