Signalr: Optional Parameters

Created on 19 Apr 2012  ·  19Comments  ·  Source: SignalR/SignalR

A minor issue I came across today. The client fails to make a call to a server method (error: Value cannot be null), if the server method accepts optional parameters and the client call excludes the optional parameter:

Server:

public void GetAll(long Id, bool DoSomething=false)

Client:

myHub.GetAll(12);
Bug

Most helpful comment

I don't think optional parameters are working as intended. We have a call with no parameters, which I'm looking to add a parameter to.

Unfortunately there's no way to do this without breaking backwards compatibility, because our client code currently calls with no arguments, I get System.IO.InvalidDataException: Invocation provides 0 argument(s) but target expects 1 - even with a single _nullable optional parameter_.

If I have to change my client to pass a null, then I can't maintain backwards compatibility, and may as well not use the optional parameter at all 😦

Workaround: Add and call a new method with a different name, which forwards back to the original one if no parameter passed. Disappointing 👎

All 19 comments

We can make method resolution smarter.

Definitely a good idea. Started actually working on that, but reverted to push the basic dynamic hubs implementation asap at that time.

Speaking of method resolving...
With current implementation we could also add method overloads support. Named parameter resolving would be possible to add too, but that would imply some modifications to how the parameters are actually passed between client and server (passing key-value pairs instead of just values). What'd you think?

Does this also apply for a Nullable parameter? I have a method with 3 parameters, the last of which is a nullable int (int?). If I set the last parameter to null I get the exception:

Value cannot be null.
Parameter name: o

at Newtonsoft.Json.Utilities.ValidationUtils.ArgumentNotNull(Object value, String parameterName)
at Newtonsoft.Json.Linq.JToken.FromObjectInternal(Object o, JsonSerializer jsonSerializer)
at Newtonsoft.Json.Linq.JToken.FromObject(Object o, JsonSerializer jsonSerializer)
at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.InvokeT
at GeoTag.App.Core.Services.SignalRClientService.d__9.MoveNext()

Note that I have not set a default value for it on the server

We'll move this to the new repo as a v3 candidate

@JasonBSteele - I know it's been a while but the issue you are mentioning was just fixed. Expect to see it in the next release.

I'm confused as to the status of this issue. Has it been fixed in any SignalR release?

@paulirwin No

...

The fix is in 2.2.1 that shipped in July (https://github.com/SignalR/SignalR/releases/tag/2.2.1)

I retested what I ran into yesterday, here are my findings:
Hub method that client will call

public async Task EpicMethod( int? daysTillNETStandard20 ) {}

.NET client server method invocation attempts:

1. await _serviceRequestHubProxy.Invoke(nameof(ISomethingOnServerSide.EpicMethod), null).ConfigureAwait(false);

System.ArgumentNullException: Value cannot be null.
Parameter name: args
   at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[TResult,TProgress](String method, Action`1 onProgress, Object[] args)
   at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke(String method, Object[] args)

2. await _serviceRequestHubProxy.Invoke(nameof(ISomethingOnServerSide.EpicMethod), null, null).ConfigureAwait(false);

System.InvalidOperationException: 'EpicMethod' method could not be resolved. Potential candidates are: 
EpicMethod(daysTillNETStandard20:Nullable`1):Task

3. await _serviceRequestHubProxy.Invoke(nameof(ISomethingOnServerSide.EpicMethod), null, new object[] {}).ConfigureAwait(false);

System.InvalidOperationException: 'EpicMethod' method could not be resolved. Potential candidates are: 
EpicMethod(daysTillNETStandard20:Nullable`1):Task
4. await _serviceRequestHubProxy.Invoke(nameof(ISomethingOnServerSide.EpicMethod), null, new object[] {null}).ConfigureAwait(false);
System.InvalidOperationException: 'EpicMethod' method could not be resolved. Potential candidates are: 
EpicMethod(daysTillNETStandard20:Nullable`1):Task

so for now I removed nullability from the hub method and passing 0 from the client side

Reopening as per your finding...

I have this problem too. Will be resolved?

Sounds like a simple matter of the binder not converting null to a Nullable<T>. I'll investigate.

So turns out that this is actually by design. How you should actually be passing in an object array with the value of null. Like this using your example
await _serviceRequestHubProxy.Invoke(nameof(ISomethingOnServerSide.EpicMethod), new object[] {null}).ConfigureAwait(false);

What you were doing was setting the params array that the parameter resolver was using to null instead of passing in a null value into a params array.

Is the problem supposed to be solved in the current version? Since the Issue date was 5 years ago, But Optional parameters still doesn't work for me?

@AlameerAshraf - show exactly what you are trying to do. I don't think there are any plans to change anything in this area at this point.

I don't think optional parameters are working as intended. We have a call with no parameters, which I'm looking to add a parameter to.

Unfortunately there's no way to do this without breaking backwards compatibility, because our client code currently calls with no arguments, I get System.IO.InvalidDataException: Invocation provides 0 argument(s) but target expects 1 - even with a single _nullable optional parameter_.

If I have to change my client to pass a null, then I can't maintain backwards compatibility, and may as well not use the optional parameter at all 😦

Workaround: Add and call a new method with a different name, which forwards back to the original one if no parameter passed. Disappointing 👎

I really think that optional method parameters and overloading should be supported - this might be overdue actually as it's common to use both and counter-intuitive not to use them when using SignalR.

Here in 2020 method overloading works but optional parameters don't, anyway I think it is still easy to simply call parametrized method from non parametrized and keeping backward compatibility.

Was this page helpful?
0 / 5 - 0 ratings