InvokeMethodAsync API is too permissive for DAPR 0.7
See original GitHub issueI just upgraded my small DAPR playground project from 0.6 to 0.7. After that, my remote invocation calls stopped working with the following exception:
Grpc.Core.RpcException: Status(StatusCode=InvalidArgument, Detail="missing HTTP extension field")
at Dapr.Client.DaprClientGrpc.MakeGrpcCallHandleError[TResponse](Func`2 callFunc, CancellationToken cancellationToken)
at Dapr.Client.DaprClientGrpc.MakeInvokeRequestAsync(String appId, String methodName, Any data, HTTPExtension httpExtension, CancellationToken cancellationToken)
at Dapr.Client.DaprClientGrpc.InvokeMethodAsync[TRequest,TResponse](String appId, String methodName, TRequest data, HTTPExtension httpExtension, CancellationToken cancellationToken)
at DotNetBa.Dapr.Main.Controllers.UserController.Login(LoginModel model, DaprClient dapr, CancellationToken cancellationToken) in C:\Source\Personal\dotnetba-dapr\src\DotNetBa.Dapr.Main\Controllers\UserController.cs:line 44
at lambda_method(Closure , Object )
at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult()
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
I traced this to the following DAPR source: https://github.com/dapr/dapr/blob/41df721108185a399cf6c9096fe414bacb1d8b5d/pkg/channel/http/http_channel.go#L68
This looks like the remote invocation now requires the HTTPExtension
to be specified. However, the call to InvokeMethodAsync
marks that parameter as optional with default value of null
(all overloads):
https://github.com/dapr/dotnet-sdk/blob/44ca6496d8c29e14df2122f6704d24b38a1755a4/src/Dapr.Client/DaprClient.cs#L59-L63
This allows the user to write valid code that cannot work at runtime. I think the API surface should be made stricter to prevent this user error:
// original code - worked in 0.6 and broke in 0.7 (compiles in both)
await dapr.InvokeMethodAsync<LoginRequest, LoginResponse>(Apps.UserService,
"login/login",
request,
cancellationToken: cancellationToken);
// new code - works in 0.7
await dapr.InvokeMethodAsync<LoginRequest, LoginResponse>(Apps.UserService,
"login/login",
request,
new HTTPExtension() { Verb = HTTPVerb.Post },
cancellationToken: cancellationToken)
This constitutes a breaking change that has not been documented (or maybe I just wasn’t able to find it). Therefore I’d like to propose a slight change to the API that would make the HTTPExtension
parameter required.
Issue Analytics
- State:
- Created 3 years ago
- Reactions:1
- Comments:10 (9 by maintainers)
Top GitHub Comments
I have updated release note and create the pr to add additional comment.
I will add this breaking change to release note as well.