RpcException when calling MoveNext C#

2,398 views
Skip to first unread message

tycz...@gmail.com

unread,
Oct 2, 2018, 11:24:46 PM10/2/18
to grpc.io
I wrote a small WPF application that just displays messages sent to my grpc server but sometimes when I connect i get this error

System.AggregateException
  HResult=0x80131500
  Message=One or more errors occurred.
  Source=mscorlib
  StackTrace:
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken)
   at System.Threading.Tasks.Task.Wait()
   at WpfApp1.MainWindow.Connect() in MainWindow.xaml.cs:line 64
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()
Inner Exception 1:
RpcException: Status(StatusCode=Unknown, Detail="Exception was thrown by handler.")
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Grpc.Core.Internal.ClientResponseStream`2.<MoveNext>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at WpfApp1.LogClient.<ConnectAndListenForMessage>d__3.MoveNext()

If I stop running the program in visual studio and start it again it seems to go away but will then come back again once I stop it and try to restart it another time. I am not sure what the issue is here but I can consistently get it to happen.

This is all my wpf app does

namespace WpfApp1
{


   
public class LogClient
   
{
       
readonly Logger.Logger.LoggerClient client;
       
RichTextBox rtb;


       
public LogClient(Logger.Logger.LoggerClient client, RichTextBox rtb)
       
{
           
this.client = client;
           
this.rtb = rtb;
       
}


       
public async Task ConnectAndListenForMessage(Logger.LogMessage message)
       
{
           
var call = client.SendLogMessages();
            await call
.RequestStream.WriteAsync(message);
           
while (await call.ResponseStream.MoveNext()) //Error happens here
           
{
               
var newMessage = call.ResponseStream.Current;
                await
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
               
{
                    rtb
.AppendText(newMessage.Message);
                    rtb
.AppendText(Environment.NewLine);
               
}), DispatcherPriority.Background);
           
}
       
}
   
}
   
/// <summary>
   
/// Interaction logic for MainWindow.xaml
   
/// </summary>
   
public partial class MainWindow : Window
   
{
       
public MainWindow()
       
{
           
InitializeComponent();


           
Thread thread = new Thread(Connect);
            thread
.Start();
       
}


       
private void Connect()
       
{
           
try
           
{
               
Logger.LogMessage message = new Logger.LogMessage();
                message
.ClientType = 1;
                message
.Message = "connecting";


               
Channel channel = new Channel("192.168.1.223", 50051, ChannelCredentials.Insecure);


               
LogClient client = new LogClient(new Logger.Logger.LoggerClient(channel), rtb);


                client
.ConnectAndListenForMessage(message).Wait();
           
}
           
catch (Exception e)
           
{
               
Console.Write(e.StackTrace);
           
}
       
}
   
}
}

Does anyone know what the issue is?

Benjamin Krämer

unread,
Oct 3, 2018, 4:28:10 PM10/3/18
to grpc.io
Looks to my like the server side threw an exception. Can you also paste the server side?

Benjamin Krämer

unread,
Oct 3, 2018, 4:33:47 PM10/3/18
to grpc.io
If you have a look at https://github.com/grpc/grpc/blob/master/src/csharp/Grpc.Core/Internal/ServerCallHandler.cs#L340 this usually happens if the server throws any exception that is not of the type RpcException.

tycz...@gmail.com

unread,
Oct 3, 2018, 10:44:41 PM10/3/18
to grpc.io
Here is the server code

class Program
   
{
       
static void Main(string[] args)
       
{
           
Server server = new Server
           
{
               
Services = { Logger.Logger.BindService(new LoggerImp()) },
               
Ports = { new ServerPort("192.168.1.223", 50051, ServerCredentials.Insecure) }
           
};
            server
.Start();


           
Console.WriteLine("Greeter server listening on port " + 50051);
           
Console.WriteLine("Press any key to stop the server...");
           
Console.ReadKey();


            server
.ShutdownAsync().Wait();
       
}
   
}


class LoggerImp : Logger.Logger.LoggerBase
   
{
       
private HashSet<IServerStreamWriter<LogMessage>> listeners = new HashSet<IServerStreamWriter<LogMessage>>();


       
public override Task ListenForMessages(LogListener request, IServerStreamWriter<LogMessage> responseStream, ServerCallContext context)
       
{
           
return base.ListenForMessages(request, responseStream, context);
       
}


       
public override async Task SendLogMessages(IAsyncStreamReader<LogMessage> requestStream, IServerStreamWriter<LogMessage> responseStream, ServerCallContext context)
       
{
            listeners
.Add(responseStream);


           
while (await requestStream.MoveNext())
           
{
               
var current = requestStream.Current;
               
if (current.ClientType == 1)
               
{
                    listeners
.Add(responseStream);
               
}


               
foreach (IServerStreamWriter<LogMessage> listener in listeners)
               
{
                   
try
                   
{
                        await listener
.WriteAsync(current);
                   
}
                   
catch (Exception)
                   
{
                       
//client stream no longer exists so remove it from list of active streams
                        listeners
.Remove(listener);
                   
}


               
}
           
}
       
}
   
}

The server will throw an error on the line 

await listener.WriteAsync(current);

if the stream is no longer active (ie. I stopped the wpf app, started it again and the server tries to send a message to a stream that does not exist) I expected this but when this happens this also throws that RpcException in the Wpf app which I didn't think would happen because I am catching the exception on the server when I try to write to the stream but it still seems to propagate back to the client.

What I am trying to do is keep a list of all streams of a certain client type, these streams then see any message that comes in from any client.

Jan Tattermusch

unread,
Oct 4, 2018, 6:31:53 AM10/4/18
to grpc.io
This doesn't look like a problem with gRPC itself.
The RpcException: Status(StatusCode=Unknown, Detail="Exception was thrown by handler.") only happens if the handler code (written by you) throws an exception. Under normal circumstances, handlers should not do that and if they the you as the author of the hander are responsible for what they throw. To me this looks like a problem in your code somewhere.
I'd suggest wrapping the entire handler body in try .. catch(Exception e) block and see what lines throws the exception and then dealing with it based on what kind of exception it turns out to be (It's that info already in the logs?).

Benjamin Krämer

unread,
Oct 4, 2018, 2:27:48 PM10/4/18
to grpc.io
I think technically, the while (await requestStream.MoveNext()) on your server side could also throw an exception if the client stream throws an exception. But since all Tasks seems to be awaited and since you get back in the while loop, this shouldn't be the problem. My best guess is that any of the listeners.Add or listeners.Remove calls throw an exception due to concurrent access (likely remove itterates through the entries and add/remove modifies the list).

As Jan suggested, the easiest way to find out is to wrap the entire handler into a try-catch block and just look at the exception there as it's definetly caused by an undealt exception from the user code.
Message has been deleted

tycz...@gmail.com

unread,
Oct 4, 2018, 9:35:56 PM10/4/18
to grpc.io
Yup, looks like you were right about the concurrent access as it throws another exception when trying to remove from the HashSet thanks!
Reply all
Reply to author
Forward
0 new messages