2

I have an app started in Dapr that has a gRPC service. Starting Dapr with id MyGrpcApi001. HTTP Port: 55319. gRPC Port: 55320

I have started it with the following command:

dapr run --app-id MyGrpcApi001 --app-protocol grpc --app-port 5000 -- dotnet run

proto:

syntax = "proto3";

import "google/protobuf/empty.proto";

option csharp_namespace = "MyGrpcService";

package greet;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
  rpc Test (google.protobuf.Empty) returns (google.protobuf.Empty);
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

I have a client that has 2 methods that connect using gRPC to the service

  • one does the call to the service directly via auto-generated client
  • another through dapr sidecar gRPC port
    class Program
    {
        private static string LOCAL_ADDRESS = @"http://localhost:5000";
        private static string DAPR_ADDRESS = $"http://localhost:55320";

        static async Task Main(string[] args)
        {
            await CallToLocalHost().ConfigureAwait(false); // runs OK
            await CallWithClient().ConfigureAwait(false); // exception: Service is unimplemented
        }

        private static async Task CallToLocalHost()
        {
            using var channel = GrpcChannel.ForAddress(LOCAL_ADDRESS);
            var cl = new MyGrpcService.Greeter.GreeterClient(channel);
            MyGrpcService.HelloReply response = await cl.SayHelloAsync(new MyGrpcService.HelloRequest { Name = "ThinkPad" });
            Console.WriteLine(response.Message);
        }

        private static async Task CallWithClient()
        {
            using DaprClient client = new DaprClientBuilder()
                     .UseGrpcEndpoint(DAPR_ADDRESS)
                     .Build();

            var request = new MyGrpcService.HelloRequest { Name = "ThinkPad" };
            var result = await client.InvokeMethodGrpcAsync<MyGrpcService.HelloRequest, MyGrpcService.HelloReply>("MyGrpcApi001", "SayHello", request).ConfigureAwait(false);
        }
    }

the second method does not seem to work, so the direct call works, but the sidecar does not seem to find the service. Here are the logs for both:

the logs from the running service:

First method OK:

== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
== APP ==       Request starting HTTP/2 POST http://localhost:5000/greet.Greeter/SayHello application/grpc -
== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
== APP ==       Executing endpoint 'gRPC - /greet.Greeter/SayHello'
== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
== APP ==       Executed endpoint 'gRPC - /greet.Greeter/SayHello'
== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
== APP ==       Request finished HTTP/2 POST http://localhost:5000/greet.Greeter/SayHello application/grpc - - 200 - application/grpc 0.3074ms

Second method Error:

== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
== APP ==       Request starting HTTP/2 POST http://127.0.0.1:5000/dapr.proto.runtime.v1.AppCallback/OnInvoke application/grpc -
== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[0]
== APP ==       Executing endpoint 'gRPC - Unimplemented service'
== APP == info: Grpc.AspNetCore.Server.Internal.ServerCallHandlerFactory[1]
== APP ==       Service 'dapr.proto.runtime.v1.AppCallback' is unimplemented.
== APP == info: Microsoft.AspNetCore.Routing.EndpointMiddleware[1]
== APP ==       Executed endpoint 'gRPC - Unimplemented service'
== APP == info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
== APP ==       Request finished HTTP/2 POST http://127.0.0.1:5000/dapr.proto.runtime.v1.AppCallback/OnInvoke application/grpc - - 200 0 application/grpc 0.1474ms

the second one seems to have the wrong URL that includes /dapr.proto.runtime. ...

What am I doing wrong here? Is the dapr run command wrong, or do I have the wrong parameters for the InvokeMethodGrpcAsync method?

Since I can run the method directly through the auto-generated client, I think that the server works OK, it is that dapr does not find the service and/or the methods.

Any ideas?

Thanks!

tridy
  • 1,166
  • 1
  • 12
  • 21

2 Answers2

2

I had this same issue calling a gRPC service. The Greeter service looked like this, which the gRPC call could not resolve with the issue 'gRPC - Unimplemented service'.

public class GreeterService : Greeter.GreeterBase
{
    public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
    {
        return Task.FromResult(new HelloReply
        {
            Message = "Hello " + request.Name
        });
    }
}

Inheriting from the AppCallbackBase class instead fixed the issue.

public class GreeterService : AppCallback.AppCallbackBase
{
    public override async Task<InvokeResponse> OnInvoke(InvokeRequest request, ServerCallContext context)
    {
        InvokeResponse response = new();
        switch (request.Method)
        {
            case "SayHello":
                HelloRequest input = request.Data.Unpack<HelloRequest>();
                HelloReply output = await Task.FromResult(new HelloReply() { Message = "Hello " + input.Name });
                response.Data = Any.Pack(output);
                break;
            default:
                Console.WriteLine("Method not supported");
                break;
        }

        return response;
    }
}
hawky
  • 116
  • 6
0

When i call the dapr grpc port, i prefer use Dapr Grpc Proxy and add service id inside GRPC metadata channel because i can use directly GRPC methods.

you can read the the documentation

But you need add preview Dapr feature inside Dapr configuration.yml file:

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: serverconfig
spec:
  features:
    - name: proxy.grpc
      enabled: true

you can check the method DaprClient.CreateInvocationInvoker inside .Net SDK

public static CallInvoker CreateInvocationInvoker(string appId, string daprEndpoint = null, string daprApiToken = null)
{
    var channel = GrpcChannel.ForAddress(daprEndpoint ?? DaprDefaults.GetDefaultGrpcEndpoint());
    return channel.Intercept(new InvocationInterceptor(appId, daprApiToken ?? DaprDefaults.GetDefaultApiToken()));
}

The code add a key value inside Grpc channel: "dapr-app-id": {{your app id}}

Example:

var callInvoker = DaprClient.CreateInvocationInvoker("my-app-id");
var tenantServiceClient = 
    new TenantService.TenantServiceClient(callInvoker);
var tenantModel = await tenantServiceClient.FindOneAsync(new FindOneTenantRequest()
                {
                    Id = tenantId
                });
spottedmahn
  • 14,823
  • 13
  • 108
  • 178
Thetyne
  • 206
  • 1
  • 3