public abstract ValueTask Invoke(StreamingHubContext context);
async Task HandleMessageAsync() { var ct = Context.CallContext.CancellationToken; var reader = Context.RequestStream !; var writer = Context.ResponseStream !; // Send a hint to the client to start sending messages. // The client can read the response headers before any StreamingHub's message. await Context.CallContext.WriteResponseHeadersAsync(ResponseHeaders); var handlers = StreamingHubHandlerRepository.GetHandlers(Context.MethodHandler); // Main loop of StreamingHub. // Be careful to allocation and performance. while (await reader.MoveNext(ct)) // must keep SyncContext. { (int methodId, int messageId, int offset) FetchHeader(byte[] msgData) { var messagePackReader = new MessagePackReader(msgData); var length = messagePackReader.ReadArrayHeader(); if (length == 2) { // void: [methodId, [argument]] var mid = messagePackReader.ReadInt32(); var consumed = (int)messagePackReader.Consumed; return(mid, -1, consumed); } else if (length == 3) { // T: [messageId, methodId, [argument]] var msgId = messagePackReader.ReadInt32(); var metId = messagePackReader.ReadInt32(); var consumed = (int)messagePackReader.Consumed; return(metId, msgId, consumed); } else { throw new InvalidOperationException("Invalid data format."); } } var data = reader.Current; var(methodId, messageId, offset) = FetchHeader(data); if (messageId == -1) { if (handlers.TryGetValue(methodId, out var handler)) { var context = new StreamingHubContext() // create per invoke. { AsyncWriterLock = Context.AsyncWriterLock, SerializerOptions = handler.serializerOptions, HubInstance = this, ServiceContext = Context, Request = new ArraySegment <byte>(data, offset, data.Length - offset), Path = handler.ToString(), MethodId = handler.MethodId, MessageId = -1, Timestamp = DateTime.UtcNow }; var isErrorOrInterrupted = false; Context.MethodHandler.logger.BeginInvokeHubMethod(context, context.Request, handler.RequestType); try { await handler.MethodBody.Invoke(context); } catch (Exception ex) { isErrorOrInterrupted = true; Context.MethodHandler.logger.Error(ex, context); } finally { Context.MethodHandler.logger.EndInvokeHubMethod(context, context.responseSize, context.responseType, (DateTime.UtcNow - context.Timestamp).TotalMilliseconds, isErrorOrInterrupted); } } else { throw new InvalidOperationException("Handler not found in received methodId, methodId:" + methodId); } } else { if (handlers.TryGetValue(methodId, out var handler)) { var context = new StreamingHubContext() // create per invoke. { AsyncWriterLock = Context.AsyncWriterLock, SerializerOptions = handler.serializerOptions, HubInstance = this, ServiceContext = Context, Request = new ArraySegment <byte>(data, offset, data.Length - offset), Path = handler.ToString(), MethodId = handler.MethodId, MessageId = messageId, Timestamp = DateTime.UtcNow }; var isErrorOrInterrupted = false; Context.MethodHandler.logger.BeginInvokeHubMethod(context, context.Request, handler.RequestType); try { await handler.MethodBody.Invoke(context); } catch (ReturnStatusException ex) { await context.WriteErrorMessage((int)ex.StatusCode, ex.Detail, null, false); } catch (Exception ex) { isErrorOrInterrupted = true; Context.MethodHandler.logger.Error(ex, context); await context.WriteErrorMessage((int)StatusCode.Internal, $"An error occurred while processing handler '{handler.ToString()}'.", ex, Context.MethodHandler.isReturnExceptionStackTraceInErrorDetail); } finally { Context.MethodHandler.logger.EndInvokeHubMethod(context, context.responseSize, context.responseType, (DateTime.UtcNow - context.Timestamp).TotalMilliseconds, isErrorOrInterrupted); } } else { throw new InvalidOperationException("Handler not found in received methodId, methodId:" + methodId); } } } }
async Task HandleMessageAsync() { var ct = Context.CallContext.CancellationToken; var reader = Context.RequestStream; var writer = Context.ResponseStream; var handlers = StreamingHubHandlerRepository.GetHandlers(Context.MethodHandler); // Main loop of StreamingHub. // Be careful to allocation and performance. while (await reader.MoveNext(ct)) { var data = reader.Current; var length = MessagePackBinary.ReadArrayHeader(data, 0, out var readSize); var offset = readSize; if (length == 2) { // void: [methodId, [argument]] var methodId = MessagePackBinary.ReadInt32(data, offset, out readSize); offset += readSize; if (handlers.TryGetValue(methodId, out var handler)) { var context = new StreamingHubContext() // create per invoke. { AsyncWriterLock = Context.AsyncWriterLock, FormatterResolver = handler.resolver, HubInstance = this, ServiceContext = Context, Request = new ArraySegment <byte>(data, offset, data.Length - offset), Path = handler.ToString(), MethodId = handler.MethodId, MessageId = -1, Timestamp = DateTime.UtcNow }; var isErrorOrInterrupted = false; Context.MethodHandler.logger.BeginInvokeHubMethod(context, context.Request, handler.RequestType); try { await handler.MethodBody.Invoke(context); } catch (Exception ex) { isErrorOrInterrupted = true; LogError(ex, context); } finally { Context.MethodHandler.logger.EndInvokeHubMethod(context, context.responseSize, context.responseType, (DateTime.UtcNow - context.Timestamp).TotalMilliseconds, isErrorOrInterrupted); } } else { throw new InvalidOperationException("Handler not found in received methodId, methodId:" + methodId); } } else if (length == 3) { // T: [messageId, methodId, [argument]] var messageId = MessagePackBinary.ReadInt32(data, offset, out readSize); offset += readSize; var methodId = MessagePackBinary.ReadInt32(data, offset, out readSize); offset += readSize; if (handlers.TryGetValue(methodId, out var handler)) { var context = new StreamingHubContext() // create per invoke. { AsyncWriterLock = Context.AsyncWriterLock, FormatterResolver = handler.resolver, HubInstance = this, ServiceContext = Context, Request = new ArraySegment <byte>(data, offset, data.Length - offset), Path = handler.ToString(), MethodId = handler.MethodId, MessageId = messageId, Timestamp = DateTime.UtcNow }; var isErrorOrInterrupted = false; Context.MethodHandler.logger.BeginInvokeHubMethod(context, context.Request, handler.RequestType); try { await handler.MethodBody.Invoke(context); } catch (ReturnStatusException ex) { await context.WriteErrorMessage((int)ex.StatusCode, ex.Detail, null, false); } catch (Exception ex) { LogError(ex, context); await context.WriteErrorMessage((int)StatusCode.Internal, "Erorr on " + handler.ToString(), ex, Context.MethodHandler.isReturnExceptionStackTraceInErrorDetail); } finally { Context.MethodHandler.logger.EndInvokeHubMethod(context, context.responseSize, context.responseType, (DateTime.UtcNow - context.Timestamp).TotalMilliseconds, isErrorOrInterrupted); } } else { throw new InvalidOperationException("Handler not found in received methodId, methodId:" + methodId); } } else { throw new InvalidOperationException("Invalid data format."); } } }
void LogError(Exception ex, StreamingHubContext context) { Logger.Error(ex, "StreamingHubHandler throws exception occured in " + context.Path); }
public abstract ValueTask Invoke(StreamingHubContext context, Func <StreamingHubContext, ValueTask> next);