public static async Task WriteSingleMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer) where TResponse : class { var logger = serverCallContext.Logger; try { // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader var httpResponse = serverCallContext.HttpContext.Response; if (!httpResponse.HasStarted) { await httpResponse.StartAsync(); } GrpcServerLog.SendingMessage(logger); var serializationContext = serverCallContext.SerializationContext; serializationContext.Reset(); serializationContext.ResponseBufferWriter = pipeWriter; serializer(response, serializationContext); GrpcServerLog.MessageSent(serverCallContext.Logger); GrpcEventSource.Log.MessageSent(); } catch (Exception ex) { GrpcServerLog.ErrorSendingMessage(logger, ex); throw; } }
public static async Task WriteStreamedMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, CancellationToken cancellationToken = default) where TResponse : class { var logger = serverCallContext.Logger; try { // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader var httpResponse = serverCallContext.HttpContext.Response; if (!httpResponse.HasStarted) { await httpResponse.StartAsync(); } GrpcServerLog.SendingMessage(logger); var serializationContext = serverCallContext.SerializationContext; serializationContext.Reset(); serializationContext.ResponseBufferWriter = pipeWriter; serializer(response, serializationContext); // Flush messages unless WriteOptions.Flags has BufferHint set var flush = ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint; if (flush) { var flushResult = await pipeWriter.FlushAsync(); // Workaround bug where FlushAsync doesn't return IsCanceled = true on request abort. // https://github.com/dotnet/aspnetcore/issues/40788 // Also, sometimes the request CT isn't triggered. Also check CT passed into method. if (!flushResult.IsCompleted && (serverCallContext.CancellationToken.IsCancellationRequested || cancellationToken.IsCancellationRequested)) { throw new OperationCanceledException("Request aborted while sending the message."); } } GrpcServerLog.MessageSent(serverCallContext.Logger); GrpcEventSource.Log.MessageSent(); } catch (Exception ex) { GrpcServerLog.ErrorSendingMessage(logger, ex); throw; } }
public static async Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, bool canFlush) where TResponse : class { var logger = serverCallContext.Logger; try { // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader var httpResponse = serverCallContext.HttpContext.Response; if (!httpResponse.HasStarted) { await httpResponse.StartAsync(); } GrpcServerLog.SendingMessage(logger); var serializationContext = serverCallContext.SerializationContext; serializationContext.Reset(); serializationContext.ResponseBufferWriter = pipeWriter; serializer(response, serializationContext); // Flush messages unless WriteOptions.Flags has BufferHint set var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint; if (flush) { serverCallContext.HasBufferedMessage = false; await pipeWriter.FlushAsync(); } else { // Set flag so buffered message will be written at the end serverCallContext.HasBufferedMessage = true; } GrpcServerLog.MessageSent(serverCallContext.Logger); GrpcEventSource.Log.MessageSent(); } catch (Exception ex) { GrpcServerLog.ErrorSendingMessage(logger, ex); throw; } }
public static async Task WriteMessageAsync <TResponse>(this PipeWriter pipeWriter, TResponse response, HttpContextServerCallContext serverCallContext, Action <TResponse, SerializationContext> serializer, bool canFlush) where TResponse : class { var logger = serverCallContext.Logger; try { GrpcServerLog.SendingMessage(logger); var serializationContext = serverCallContext.SerializationContext; serializer(response, serializationContext); var responsePayload = serializationContext.Payload; serializationContext.Payload = null; if (responsePayload == null) { throw new InvalidOperationException("Serialization did not return a payload."); } GrpcServerLog.SerializedMessage(serverCallContext.Logger, typeof(TResponse), responsePayload.Length); // Must call StartAsync before the first pipeWriter.GetSpan() in WriteHeader var httpResponse = serverCallContext.HttpContext.Response; if (!httpResponse.HasStarted) { await httpResponse.StartAsync(); } var canCompress = GrpcProtocolHelpers.CanWriteCompressed(serverCallContext.WriteOptions) && !string.Equals(serverCallContext.ResponseGrpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal); var isCompressed = false; if (canCompress) { Debug.Assert( serverCallContext.ServiceOptions.ResolvedCompressionProviders != null, "Compression providers should have been resolved for service."); if (TryCompressMessage( serverCallContext.Logger, serverCallContext.ResponseGrpcEncoding !, serverCallContext.ServiceOptions.ResponseCompressionLevel, serverCallContext.ServiceOptions.ResolvedCompressionProviders, responsePayload, out var result)) { responsePayload = result; isCompressed = true; } } if (responsePayload.Length > serverCallContext.ServiceOptions.MaxSendMessageSize) { throw new RpcException(SendingMessageExceedsLimitStatus); } WriteHeader(pipeWriter, responsePayload.Length, isCompressed); pipeWriter.Write(responsePayload); // Flush messages unless WriteOptions.Flags has BufferHint set var flush = canFlush && ((serverCallContext.WriteOptions?.Flags ?? default) & WriteFlags.BufferHint) != WriteFlags.BufferHint; if (flush) { serverCallContext.HasBufferedMessage = false; await pipeWriter.FlushAsync(); } else { // Set flag so buffered message will be written at the end serverCallContext.HasBufferedMessage = true; } GrpcServerLog.MessageSent(serverCallContext.Logger); GrpcEventSource.Log.MessageSent(); } catch (Exception ex) { GrpcServerLog.ErrorSendingMessage(logger, ex); throw; } }