Grpc.Core.RpcException method is unimplemented with C# client and Java Server
Asked Answered
T

6

23

I am having trouble finding the source of this error. I implemented a simple service using protobuf:

syntax = "proto3";

package tourism;

service RemoteService {
  rpc Login(LoginUserDTO) returns (Response) {}
}

message AgencyDTO{
  int32 id=1;
  string name=2;
  string email=3;
  string password=4;
}

message LoginUserDTO{
  string password=1;
  string email=2;
}

message SearchAttractionsDTO{
  string name=1;
  int32 start_hour=2;
  int32 start_minute=3;
  int32 stop_hour=4;
  int32 stop_minute=5;
  AgencyDTO loggedUser=6;
}

message AttractionDTO{
  int32 id=1;
  string name=2;
  string agency=3;
  int32 hour=4;
  int32 minute=5;
  int32 seats=6;
  int32 price=7;
}

message ReservationDTO{
  int32 id=1;
  string first_name=2;
  string last_name=3;
  string phone=4;
  int32 seats=5;
  AttractionDTO attraction=6;
  AgencyDTO agency=7;
}

message Response{
  enum ResponseType{
    OK=0;
    NOT_LOGGED_ID=1;
    SERVER_ERROR=2;
    VALIDATOR_ERROR=3;
  }
  ResponseType type=1;
  AgencyDTO user=2;
  string message=3;
}

When using a java client everything works fine, the server receives the request and responds appropriately. When using C# with the same .proto file for generating sources at the client.Login() I get the following errror: Grpc.Core.RpcException Status(StatusCode=Unimplemented, Detail="Method tourism.RemoteService/Login is unimplemented"). The server receives the request but does not have time to respond and throws:

INFO: Request from [email protected]
May 22, 2017 12:28:58 AM io.grpc.internal.SerializingExecutor run
SEVERE: Exception while executing runnable io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2@4be43082
java.lang.IllegalStateException: call is closed
    at com.google.common.base.Preconditions.checkState(Preconditions.java:174)
    at io.grpc.internal.ServerCallImpl.sendHeaders(ServerCallImpl.java:103)
    at io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(ServerCalls.java:282)
    at ServiceImp.login(ServiceImp.java:20)
    at tourism.RemoteServiceGrpc$MethodHandlers.invoke(RemoteServiceGrpc.java:187)
    at io.grpc.stub.ServerCalls$1$1.onHalfClose(ServerCalls.java:148)
    at io.grpc.internal.ServerCallImpl$ServerStreamListenerImpl.halfClosed(ServerCallImpl.java:262)
    at io.grpc.internal.ServerImpl$JumpToApplicationThreadServerStreamListener$2.runInContext(ServerImpl.java:572)
    at io.grpc.internal.ContextRunnable.run(ContextRunnable.java:52)
    at io.grpc.internal.SerializingExecutor.run(SerializingExecutor.java:117)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)

Java server:

import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import tourism.RemoteServiceGrpc;
import tourism.Service;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Created by Andu on 21/05/2017.
 */
public class ServerGrpc {
    Logger logger= Logger.getLogger(ServerGrpc.class.getName());
    private final Server server;
    private final int port;

    public ServerGrpc(int p){
        port=p;
        server= ServerBuilder.forPort(port).addService(new ServiceImp()).build();
    }

    public void start() throws IOException {
        server.start();
        logger.info("Server started, listening on " + port);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                // Use stderr here since the logger may has been reset by its JVM shutdown hook.
                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                ServerGrpc.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

    public void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    private class ServiceImp extends RemoteServiceGrpc.RemoteServiceImplBase {
        Logger log=Logger.getLogger(ServiceImp.class.getName());

        @Override
        public void login(Service.LoginUserDTO request, StreamObserver<Service.Response> responseStreamObserver){
            super.login(request,responseStreamObserver);
            log.log(Level.INFO,"Request from "+request.getEmail());
            Service.Response response= Service.Response.newBuilder().setMessage("Hello "+request.getEmail()+", I know your password: "+request.getPassword()).build();
            responseStreamObserver.onNext(response);
            responseStreamObserver.onCompleted();
        }
    }

}

C# Client:

namespace testGrpc2
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            var channel = new Channel("127.0.0.1:61666",ChannelCredentials.Insecure);
            var client = new RemoteService.RemoteServiceClient(channel);
            Response response=client.Login(new LoginUserDTO{Email="[email protected]",Password="notmypassword"});
            Console.WriteLine(response);
            Console.ReadKey();
        }
    }
} 
Trunnion answered 21/5, 2017 at 21:44 Comment(0)
T
30

I managed to find the source of the problem. For anyone else having this problem:

Make sure your .proto file is identical for both client and server and it has the same package. When the client calls a method on the remote server, it uses the full name of the remote class and the package.

However this was not the reason why the method appeared as unimplemented to the client. It was this:

super.login(request,responseStreamObserver);

Calling the super method login sends an async UNIMPLEMENTED error code back to the client. This is the login() method in the generated class:

public void login(LoginUserDTO request,StreamObserver<Response> responseObserver) {
          asyncUnimplementedUnaryCall(METHOD_LOGIN, responseObserver);
}

So make sure in the implementation of your service methods you don't call the super method as it will appear to the client as UNIMPLEMENTED. If you generate @Override methods using IntelliJ IDEA it will add the super method call. Make sure to delete it.

Trunnion answered 22/5, 2017 at 13:57 Comment(2)
for those, requiring more info on Java grpc.io/docs/reference/java/generated-codeBuhl
I had the same problem with C# Server/Client. Initially didn't click that super class in Java is equivalent to a base class in C#. On 2nd viewing a few hours later, it all made sense. Thanks!Bent
M
32

For me it was that I forget adding endpoint of gRpc service in startup class.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseRouting();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<GreeterService>();

            //Add your endpoint here like this
            endpoints.MapGrpcService<YourProtoService>();
        });
    
Magnesia answered 23/3, 2021 at 4:12 Comment(3)
This was exactly my problem, I had splitted in 2 different protos and forgot to register the new one.Saba
Gaaaa. I'm a newbie! And this was my newbie snapfu. Thanks.Triennium
app.MapGrpcService<GreeterService>(); app.MapGrpcService<ProductsAppService>();Preconceive
T
30

I managed to find the source of the problem. For anyone else having this problem:

Make sure your .proto file is identical for both client and server and it has the same package. When the client calls a method on the remote server, it uses the full name of the remote class and the package.

However this was not the reason why the method appeared as unimplemented to the client. It was this:

super.login(request,responseStreamObserver);

Calling the super method login sends an async UNIMPLEMENTED error code back to the client. This is the login() method in the generated class:

public void login(LoginUserDTO request,StreamObserver<Response> responseObserver) {
          asyncUnimplementedUnaryCall(METHOD_LOGIN, responseObserver);
}

So make sure in the implementation of your service methods you don't call the super method as it will appear to the client as UNIMPLEMENTED. If you generate @Override methods using IntelliJ IDEA it will add the super method call. Make sure to delete it.

Trunnion answered 22/5, 2017 at 13:57 Comment(2)
for those, requiring more info on Java grpc.io/docs/reference/java/generated-codeBuhl
I had the same problem with C# Server/Client. Initially didn't click that super class in Java is equivalent to a base class in C#. On 2nd viewing a few hours later, it all made sense. Thanks!Bent
S
8

For me, using the C# client, the problem was that I wasn't overriding the generated service method.

Scrounge answered 18/6, 2021 at 7:35 Comment(0)
S
1

Thanks to Alexandru - this helped solve my problem with Akka gRPC client and Python grPC server. In my case, I had same packages and preamble in .proto file but had eliminated message classes and gRPC functions not needed for this specific use case in the Python gRPC server. When I made the .proto files identical, everything worked and I no longer received UNIMPLEMENTED errors. This is needed for languages beyond the C#/Java example cited. Thanks again.

Scofield answered 27/12, 2020 at 20:29 Comment(0)
B
0

My server and client were both java, and the problem was removed after closing and opening the project in IntelliJ!!

Blackamoor answered 12/11, 2021 at 19:35 Comment(0)
B
0

In my case, the problem was on the Server Side

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

builder.Services.AddMemoryCache();

builder.Logging.AddConsole();

//this 3 lines was missed (before builder.Build()):

    builder.Services.AddCodeFirstGrpc(config =>
    {
     config.ResponseCompressionLevel = System.IO.Compression.CompressionLevel.Optimal;
    });

var app = builder.Build();
Ballplayer answered 26/2, 2023 at 8:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.