예제 #1
0
 public abstract ValueTask Invoke(StreamingHubContext context);
예제 #2
0
        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);
                    }
                }
            }
        }
예제 #3
0
        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.");
                }
            }
        }
예제 #4
0
 void LogError(Exception ex, StreamingHubContext context)
 {
     Logger.Error(ex, "StreamingHubHandler throws exception occured in " + context.Path);
 }
예제 #5
0
 public abstract ValueTask Invoke(StreamingHubContext context, Func <StreamingHubContext, ValueTask> next);