diff --git a/src/Grpc.Net.Client/HttpClientCallInvoker.cs b/src/Grpc.Net.Client/HttpClientCallInvoker.cs
index 27cc66b00..894f708ed 100644
--- a/src/Grpc.Net.Client/HttpClientCallInvoker.cs
+++ b/src/Grpc.Net.Client/HttpClientCallInvoker.cs
@@ -32,7 +32,7 @@ namespace Grpc.Net.Client
public sealed class HttpClientCallInvoker : CallInvoker
{
private readonly HttpClient _client;
- private readonly ILoggerFactory _loggerFactory;
+ internal ILoggerFactory LoggerFactory { get; }
// Override the current time for unit testing
internal ISystemClock Clock = SystemClock.Instance;
@@ -50,7 +50,7 @@ public HttpClientCallInvoker(HttpClient client, ILoggerFactory? loggerFactory)
}
_client = client;
- _loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
+ LoggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
Deadline = DateTime.MaxValue;
}
@@ -72,6 +72,16 @@ public HttpClientCallInvoker(HttpClient client, ILoggerFactory? loggerFactory)
///
public DateTime Deadline { get; set; }
+ ///
+ /// Gets or sets the maximum message size in bytes that can be sent from the client.
+ ///
+ public int? SendMaxMessageSize { get; set; }
+
+ ///
+ /// Gets or sets the maximum message size in bytes that can be received by the client.
+ ///
+ public int? ReceiveMaxMessageSize { get; set; }
+
///
/// Invokes a client streaming call asynchronously.
/// In client streaming scenario, client sends a stream of requests and server responds with a single response.
@@ -187,7 +197,7 @@ private GrpcCall CreateGrpcCall(
}
}
- var call = new GrpcCall(method, options, Clock, _loggerFactory);
+ var call = new GrpcCall(method, options, this);
// Clean up linked cancellation token
disposeAction = linkedCts != null
diff --git a/src/Grpc.Net.Client/Internal/GrpcCall.cs b/src/Grpc.Net.Client/Internal/GrpcCall.cs
index 8c5ee9e0a..1a65d9d3f 100644
--- a/src/Grpc.Net.Client/Internal/GrpcCall.cs
+++ b/src/Grpc.Net.Client/Internal/GrpcCall.cs
@@ -37,7 +37,6 @@ internal partial class GrpcCall : IDisposable
{
private readonly CancellationTokenSource _callCts;
private readonly CancellationTokenRegistration? _ctsRegistration;
- private readonly ISystemClock _clock;
private readonly TimeSpan? _timeout;
private readonly Uri _uri;
private readonly GrpcCallScope _logScope;
@@ -54,13 +53,14 @@ internal partial class GrpcCall : IDisposable
public HttpResponseMessage? HttpResponse { get; private set; }
public CallOptions Options { get; }
public Method Method { get; }
+ public HttpClientCallInvoker CallInvoker { get; }
public ILogger Logger { get; }
public Task? SendTask { get; private set; }
public HttpContentClientStreamWriter? ClientStreamWriter { get; private set; }
public HttpContentClientStreamReader? ClientStreamReader { get; private set; }
- public GrpcCall(Method method, CallOptions options, ISystemClock clock, ILoggerFactory loggerFactory)
+ public GrpcCall(Method method, CallOptions options, HttpClientCallInvoker callInvoker)
{
// Validate deadline before creating any objects that require cleanup
ValidateDeadline(options.Deadline);
@@ -70,8 +70,8 @@ public GrpcCall(Method method, CallOptions options, ISystem
_uri = new Uri(method.FullName, UriKind.Relative);
_logScope = new GrpcCallScope(method.Type, _uri);
Options = options;
- _clock = clock;
- Logger = loggerFactory.CreateLogger>();
+ CallInvoker = callInvoker;
+ Logger = callInvoker.LoggerFactory.CreateLogger>();
if (options.CancellationToken.CanBeCanceled)
{
@@ -87,7 +87,7 @@ public GrpcCall(Method method, CallOptions options, ISystem
if (options.Deadline != null && options.Deadline != DateTime.MaxValue)
{
- var timeout = options.Deadline.GetValueOrDefault() - _clock.UtcNow;
+ var timeout = options.Deadline.GetValueOrDefault() - CallInvoker.Clock.UtcNow;
_timeout = (timeout > TimeSpan.Zero) ? timeout : TimeSpan.Zero;
}
}
@@ -302,6 +302,7 @@ public async Task GetResponseAsync()
Logger,
Method.ResponseMarshaller.ContextualDeserializer,
GrpcProtocolHelpers.GetGrpcEncoding(HttpResponse),
+ CallInvoker.ReceiveMaxMessageSize,
_callCts.Token).ConfigureAwait(false);
FinishResponse();
@@ -384,6 +385,7 @@ private void SetMessageContent(TRequest request, HttpRequestMessage message)
request,
Method.RequestMarshaller.ContextualSerializer,
grpcEncoding,
+ CallInvoker.SendMaxMessageSize,
Options.CancellationToken);
},
GrpcProtocolConstants.GrpcContentTypeHeaderValue);
diff --git a/src/Grpc.Net.Client/Internal/HttpContentClientStreamReader.cs b/src/Grpc.Net.Client/Internal/HttpContentClientStreamReader.cs
index 8f28e56b9..56d8a2a4a 100644
--- a/src/Grpc.Net.Client/Internal/HttpContentClientStreamReader.cs
+++ b/src/Grpc.Net.Client/Internal/HttpContentClientStreamReader.cs
@@ -124,6 +124,7 @@ private async Task MoveNextCore(CancellationToken cancellationToken)
_call.Logger,
_call.Method.ResponseMarshaller.ContextualDeserializer,
GrpcProtocolHelpers.GetGrpcEncoding(_httpResponse),
+ _call.CallInvoker.ReceiveMaxMessageSize,
cancellationToken).ConfigureAwait(false);
if (Current == null)
{
diff --git a/src/Grpc.Net.Client/Internal/HttpContentClientStreamWriter.cs b/src/Grpc.Net.Client/Internal/HttpContentClientStreamWriter.cs
index 228bb9f21..69073267b 100644
--- a/src/Grpc.Net.Client/Internal/HttpContentClientStreamWriter.cs
+++ b/src/Grpc.Net.Client/Internal/HttpContentClientStreamWriter.cs
@@ -131,6 +131,7 @@ await writeStream.WriteMessage(
message,
_call.Method.RequestMarshaller.ContextualSerializer,
_grpcEncoding,
+ _call.CallInvoker.SendMaxMessageSize,
_call.CancellationToken).ConfigureAwait(false);
}
catch (TaskCanceledException)
diff --git a/src/Grpc.Net.Client/Internal/StreamExtensions.cs b/src/Grpc.Net.Client/Internal/StreamExtensions.cs
index 95c90603b..7e8d22161 100644
--- a/src/Grpc.Net.Client/Internal/StreamExtensions.cs
+++ b/src/Grpc.Net.Client/Internal/StreamExtensions.cs
@@ -37,6 +37,8 @@ internal static partial class StreamExtensions
private const int MessageDelimiterSize = 4; // how many bytes it takes to encode "Message-Length"
private const int HeaderSize = MessageDelimiterSize + 1; // message length + compression flag
+ private static readonly Status SendingMessageExceedsLimitStatus = new Status(StatusCode.ResourceExhausted, "Sending message exceeds the maximum configured message size.");
+ private static readonly Status ReceivedMessageExceedsLimitStatus = new Status(StatusCode.ResourceExhausted, "Received message exceeds the maximum configured message size.");
private static readonly Status NoMessageEncodingMessageStatus = new Status(StatusCode.Internal, "Request did not include grpc-encoding value with compressed message.");
private static readonly Status IdentityMessageEncodingMessageStatus = new Status(StatusCode.Internal, "Request sent 'identity' grpc-encoding value with compressed message.");
private static Status CreateUnknownMessageEncodingMessageStatus(string unsupportedEncoding, IEnumerable supportedEncodings)
@@ -49,10 +51,11 @@ private static Status CreateUnknownMessageEncodingMessageStatus(string unsupport
ILogger logger,
Func deserializer,
string grpcEncoding,
+ int? maximumMessageSize,
CancellationToken cancellationToken)
where TResponse : class
{
- return responseStream.ReadMessageCoreAsync(logger, deserializer, grpcEncoding, cancellationToken, true, true);
+ return responseStream.ReadMessageCoreAsync(logger, deserializer, grpcEncoding, maximumMessageSize, cancellationToken, true, true);
}
public static Task ReadStreamedMessageAsync(
@@ -60,10 +63,11 @@ private static Status CreateUnknownMessageEncodingMessageStatus(string unsupport
ILogger logger,
Func deserializer,
string grpcEncoding,
+ int? maximumMessageSize,
CancellationToken cancellationToken)
where TResponse : class
{
- return responseStream.ReadMessageCoreAsync(logger, deserializer, grpcEncoding, cancellationToken, true, false);
+ return responseStream.ReadMessageCoreAsync(logger, deserializer, grpcEncoding, maximumMessageSize, cancellationToken, true, false);
}
private static async Task ReadMessageCoreAsync(
@@ -71,6 +75,7 @@ private static Status CreateUnknownMessageEncodingMessageStatus(string unsupport
ILogger logger,
Func deserializer,
string grpcEncoding,
+ int? maximumMessageSize,
CancellationToken cancellationToken,
bool canBeEmpty,
bool singleMessage)
@@ -117,6 +122,11 @@ private static Status CreateUnknownMessageEncodingMessageStatus(string unsupport
throw new InvalidDataException("Message too large.");
}
+ if (length > maximumMessageSize)
+ {
+ throw new RpcException(ReceivedMessageExceedsLimitStatus);
+ }
+
// Read message content until content length is reached
byte[] messageData;
if (length > 0)
@@ -212,6 +222,7 @@ public static async Task WriteMessage(
TMessage message,
Action serializer,
string grpcEncoding,
+ int? maximumMessageSize,
CancellationToken cancellationToken)
{
try
@@ -228,6 +239,11 @@ public static async Task WriteMessage(
throw new InvalidOperationException("Serialization did not return a payload.");
}
+ if (data.Length > maximumMessageSize)
+ {
+ throw new RpcException(SendingMessageExceedsLimitStatus);
+ }
+
var isCompressed = !string.Equals(grpcEncoding, GrpcProtocolConstants.IdentityGrpcEncoding, StringComparison.Ordinal);
if (isCompressed)
diff --git a/test/Grpc.Net.Client.Tests/AsyncClientStreamingCallTests.cs b/test/Grpc.Net.Client.Tests/AsyncClientStreamingCallTests.cs
index f43aa3e26..4430699ce 100644
--- a/test/Grpc.Net.Client.Tests/AsyncClientStreamingCallTests.cs
+++ b/test/Grpc.Net.Client.Tests/AsyncClientStreamingCallTests.cs
@@ -112,9 +112,9 @@ public async Task AsyncClientStreamingCall_Success_RequestContentSent()
await call.RequestStream.CompleteAsync().DefaultTimeout();
var requestContent = await streamTask.DefaultTimeout();
- var requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, CancellationToken.None).DefaultTimeout();
+ var requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize: null, CancellationToken.None).DefaultTimeout();
Assert.AreEqual("1", requestMessage.Name);
- requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, CancellationToken.None).DefaultTimeout();
+ requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize: null, CancellationToken.None).DefaultTimeout();
Assert.AreEqual("2", requestMessage.Name);
var responseMessage = await responseTask.DefaultTimeout();
diff --git a/test/Grpc.Net.Client.Tests/AsyncDuplexStreamingCallTests.cs b/test/Grpc.Net.Client.Tests/AsyncDuplexStreamingCallTests.cs
index 51097abf1..4b4796585 100644
--- a/test/Grpc.Net.Client.Tests/AsyncDuplexStreamingCallTests.cs
+++ b/test/Grpc.Net.Client.Tests/AsyncDuplexStreamingCallTests.cs
@@ -117,9 +117,9 @@ public async Task AsyncDuplexStreamingCall_MessagesStreamed_MessagesReceived()
Assert.IsNotNull(content);
var requestContent = await content!.ReadAsStreamAsync().DefaultTimeout();
- var requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, CancellationToken.None).DefaultTimeout();
+ var requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize: null, CancellationToken.None).DefaultTimeout();
Assert.AreEqual("1", requestMessage.Name);
- requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, CancellationToken.None).DefaultTimeout();
+ requestMessage = await requestContent.ReadStreamedMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize: null, CancellationToken.None).DefaultTimeout();
Assert.AreEqual("2", requestMessage.Name);
Assert.IsNull(responseStream.Current);
diff --git a/test/Grpc.Net.Client.Tests/AsyncUnaryCallTests.cs b/test/Grpc.Net.Client.Tests/AsyncUnaryCallTests.cs
index 1ccbddfbc..0c467221b 100644
--- a/test/Grpc.Net.Client.Tests/AsyncUnaryCallTests.cs
+++ b/test/Grpc.Net.Client.Tests/AsyncUnaryCallTests.cs
@@ -107,7 +107,7 @@ public async Task AsyncUnaryCall_Success_RequestContentSent()
Assert.IsNotNull(content);
var requestContent = await content!.ReadAsStreamAsync().DefaultTimeout();
- var requestMessage = await requestContent.ReadSingleMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, CancellationToken.None).DefaultTimeout();
+ var requestMessage = await requestContent.ReadSingleMessageAsync(NullLogger.Instance, ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer, GrpcProtocolConstants.IdentityGrpcEncoding, maximumMessageSize: null, CancellationToken.None).DefaultTimeout();
Assert.AreEqual("World", requestMessage.Name);
}
diff --git a/test/Grpc.Net.Client.Tests/CompressionTests.cs b/test/Grpc.Net.Client.Tests/CompressionTests.cs
index f084b5ce6..bd77509cd 100644
--- a/test/Grpc.Net.Client.Tests/CompressionTests.cs
+++ b/test/Grpc.Net.Client.Tests/CompressionTests.cs
@@ -38,7 +38,7 @@ namespace Grpc.Net.Client.Tests
public class CompressionTests
{
[Test]
- public void AsyncUnaryCall_UnknownCompressMetadataSentWithRequest_ThrowsError()
+ public async Task AsyncUnaryCall_UnknownCompressMetadataSentWithRequest_ThrowsError()
{
// Arrange
HttpRequestMessage? httpRequestMessage = null;
@@ -55,6 +55,7 @@ public void AsyncUnaryCall_UnknownCompressMetadataSentWithRequest_ThrowsError()
NullLogger.Instance,
ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer,
"gzip",
+ maximumMessageSize: null,
CancellationToken.None);
HelloReply reply = new HelloReply
@@ -76,7 +77,7 @@ public void AsyncUnaryCall_UnknownCompressMetadataSentWithRequest_ThrowsError()
});
// Assert
- var ex = Assert.ThrowsAsync(async () => await call.ResponseAsync.DefaultTimeout());
+ var ex = await ExceptionAssert.ThrowsAsync(() => call.ResponseAsync).DefaultTimeout();
Assert.AreEqual("Could not find compression provider for 'not-supported'.", ex.Message);
}
@@ -98,6 +99,7 @@ public async Task AsyncUnaryCall_CompressMetadataSentWithRequest_RequestMessageC
NullLogger.Instance,
ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer,
"gzip",
+ maximumMessageSize: null,
CancellationToken.None);
HelloReply reply = new HelloReply
@@ -149,6 +151,7 @@ public async Task AsyncUnaryCall_CompressedResponse_ResponseMessageDecompressed(
NullLogger.Instance,
ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer,
"gzip",
+ maximumMessageSize: null,
CancellationToken.None);
HelloReply reply = new HelloReply
@@ -176,7 +179,7 @@ public async Task AsyncUnaryCall_CompressedResponse_ResponseMessageDecompressed(
}
[Test]
- public void AsyncUnaryCall_CompressedResponseWithUnknownEncoding_ErrorThrown()
+ public async Task AsyncUnaryCall_CompressedResponseWithUnknownEncoding_ErrorThrown()
{
// Arrange
HttpRequestMessage? httpRequestMessage = null;
@@ -193,6 +196,7 @@ public void AsyncUnaryCall_CompressedResponseWithUnknownEncoding_ErrorThrown()
NullLogger.Instance,
ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer,
"gzip",
+ maximumMessageSize: null,
CancellationToken.None);
HelloReply reply = new HelloReply
@@ -214,7 +218,7 @@ public void AsyncUnaryCall_CompressedResponseWithUnknownEncoding_ErrorThrown()
});
// Assert
- var ex = Assert.ThrowsAsync(async () => await call.ResponseAsync.DefaultTimeout());
+ var ex = await ExceptionAssert.ThrowsAsync(() => call.ResponseAsync).DefaultTimeout();
Assert.AreEqual(StatusCode.Unimplemented, ex.StatusCode);
Assert.AreEqual("Unsupported grpc-encoding value 'not-supported'. Supported encodings: gzip", ex.Status.Detail);
}
diff --git a/test/Grpc.Net.Client.Tests/HttpContentClientStreamReaderTests.cs b/test/Grpc.Net.Client.Tests/HttpContentClientStreamReaderTests.cs
index d3bb91d73..06380958b 100644
--- a/test/Grpc.Net.Client.Tests/HttpContentClientStreamReaderTests.cs
+++ b/test/Grpc.Net.Client.Tests/HttpContentClientStreamReaderTests.cs
@@ -48,7 +48,8 @@ public async Task MoveNext_TokenCanceledBeforeCall_ThrowError()
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.OK, content));
});
- var call = new GrpcCall(ClientTestHelpers.ServiceMethod, new CallOptions(), SystemClock.Instance, NullLoggerFactory.Instance);
+ var httpClientCallInvoker = new HttpClientCallInvoker(httpClient, null);
+ var call = new GrpcCall(ClientTestHelpers.ServiceMethod, new CallOptions(), httpClientCallInvoker);
call.StartServerStreaming(httpClient, new HelloRequest());
// Act
@@ -73,7 +74,8 @@ public async Task MoveNext_TokenCanceledDuringCall_ThrowError()
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.OK, content));
});
- var call = new GrpcCall(ClientTestHelpers.ServiceMethod, new CallOptions(), SystemClock.Instance, NullLoggerFactory.Instance);
+ var httpClientCallInvoker = new HttpClientCallInvoker(httpClient, null);
+ var call = new GrpcCall(ClientTestHelpers.ServiceMethod, new CallOptions(), httpClientCallInvoker);
call.StartServerStreaming(httpClient, new HelloRequest());
// Act
@@ -99,7 +101,8 @@ public async Task MoveNext_MultipleCallsWithoutAwait_ThrowError()
return Task.FromResult(ResponseUtils.CreateResponse(HttpStatusCode.OK, content));
});
- var call = new GrpcCall(ClientTestHelpers.ServiceMethod, new CallOptions(), SystemClock.Instance, NullLoggerFactory.Instance);
+ var httpClientCallInvoker = new HttpClientCallInvoker(httpClient, null);
+ var call = new GrpcCall(ClientTestHelpers.ServiceMethod, new CallOptions(), httpClientCallInvoker);
call.StartServerStreaming(httpClient, new HelloRequest());
// Act
diff --git a/test/Grpc.Net.Client.Tests/MaximumMessageSizeTests.cs b/test/Grpc.Net.Client.Tests/MaximumMessageSizeTests.cs
new file mode 100644
index 000000000..656402d1d
--- /dev/null
+++ b/test/Grpc.Net.Client.Tests/MaximumMessageSizeTests.cs
@@ -0,0 +1,225 @@
+#region Copyright notice and license
+
+// Copyright 2019 The gRPC Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#endregion
+
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Threading;
+using System.Threading.Tasks;
+using Greet;
+using Grpc.Core;
+using Grpc.Net.Client.Internal;
+using Grpc.Net.Client.Internal.Compression;
+using Grpc.Net.Client.Tests.Infrastructure;
+using Grpc.Tests.Shared;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging.Abstractions;
+using NUnit.Framework;
+
+namespace Grpc.Net.Client.Tests
+{
+ [TestFixture]
+ public class MaximumMessageSizeTests
+ {
+ private async Task HandleRequest(HttpRequestMessage request)
+ {
+ var requestStream = await request.Content.ReadAsStreamAsync();
+
+ var helloRequest = await StreamExtensions.ReadSingleMessageAsync(
+ requestStream,
+ NullLogger.Instance,
+ ClientTestHelpers.ServiceMethod.RequestMarshaller.ContextualDeserializer,
+ "gzip",
+ maximumMessageSize: null,
+ CancellationToken.None);
+
+ HelloReply reply = new HelloReply
+ {
+ Message = "Hello " + helloRequest!.Name
+ };
+
+ var streamContent = await ClientTestHelpers.CreateResponseContent(reply).DefaultTimeout();
+
+ return ResponseUtils.CreateResponse(HttpStatusCode.OK, streamContent);
+ }
+
+ [Test]
+ public async Task AsyncUnaryCall_MessageSmallerThanSendMaxMessageSize_Success()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.SendMaxMessageSize = 100;
+
+ // Act
+ var call = invoker.AsyncUnaryCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest
+ {
+ Name = "World"
+ });
+
+ // Assert
+ var response = await call.ResponseAsync.DefaultTimeout();
+ Assert.AreEqual("Hello World", response.Message);
+ }
+
+ [Test]
+ public async Task AsyncUnaryCall_MessageLargerThanSendMaxMessageSize_ThrowsError()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.SendMaxMessageSize = 1;
+
+ // Act
+ var call = invoker.AsyncUnaryCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest
+ {
+ Name = "World"
+ });
+
+ // Assert
+ var ex = await ExceptionAssert.ThrowsAsync(() => call.ResponseAsync).DefaultTimeout();
+ Assert.AreEqual(StatusCode.ResourceExhausted, ex.StatusCode);
+ Assert.AreEqual("Sending message exceeds the maximum configured message size.", ex.Status.Detail);
+ }
+
+ [Test]
+ public async Task AsyncUnaryCall_MessageSmallerThanReceiveMaxMessageSize_Success()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.ReceiveMaxMessageSize = 100;
+
+ // Act
+ var call = invoker.AsyncUnaryCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest
+ {
+ Name = "World"
+ });
+
+ // Assert
+ var response = await call.ResponseAsync.DefaultTimeout();
+ Assert.AreEqual("Hello World", response.Message);
+ }
+
+ [Test]
+ public async Task AsyncUnaryCall_MessageLargerThanReceiveMaxMessageSize_ThrowsError()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.ReceiveMaxMessageSize = 1;
+
+ // Act
+ var call = invoker.AsyncUnaryCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions(), new HelloRequest
+ {
+ Name = "World"
+ });
+
+ // Assert
+ var ex = await ExceptionAssert.ThrowsAsync(() => call.ResponseAsync).DefaultTimeout();
+ Assert.AreEqual(StatusCode.ResourceExhausted, ex.StatusCode);
+ Assert.AreEqual("Received message exceeds the maximum configured message size.", ex.Status.Detail);
+ }
+
+ [Test]
+ public async Task AsyncDuplexStreamingCall_MessageSmallerThanSendMaxMessageSize_Success()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.SendMaxMessageSize = 100;
+
+ // Act
+ var call = invoker.AsyncDuplexStreamingCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions());
+ await call.RequestStream.WriteAsync(new HelloRequest
+ {
+ Name = "World"
+ });
+ await call.RequestStream.CompleteAsync();
+
+ // Assert
+ await call.ResponseStream.MoveNext(CancellationToken.None).DefaultTimeout();
+ Assert.AreEqual("Hello World", call.ResponseStream.Current.Message);
+ }
+
+ [Test]
+ public async Task AsyncDuplexStreamingCall_MessageLargerThanSendMaxMessageSize_ThrowsError()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.SendMaxMessageSize = 1;
+
+ // Act
+ var call = invoker.AsyncDuplexStreamingCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions());
+
+ // Assert
+ var ex = await ExceptionAssert.ThrowsAsync(() => call.RequestStream.WriteAsync(new HelloRequest
+ {
+ Name = "World"
+ }));
+ Assert.AreEqual(StatusCode.ResourceExhausted, ex.StatusCode);
+ Assert.AreEqual("Sending message exceeds the maximum configured message size.", ex.Status.Detail);
+ }
+
+ [Test]
+ public async Task AsyncDuplexStreamingCall_MessageSmallerThanReceiveMaxMessageSize_Success()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.ReceiveMaxMessageSize = 100;
+
+ // Act
+ var call = invoker.AsyncDuplexStreamingCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions());
+ await call.RequestStream.WriteAsync(new HelloRequest
+ {
+ Name = "World"
+ });
+ await call.RequestStream.CompleteAsync();
+
+ // Assert
+ await call.ResponseStream.MoveNext(CancellationToken.None).DefaultTimeout();
+ Assert.AreEqual("Hello World", call.ResponseStream.Current.Message);
+ }
+
+ [Test]
+ public async Task AsyncDuplexStreamingCall_MessageLargerThanReceiveMaxMessageSize_ThrowsError()
+ {
+ // Arrange
+ var httpClient = ClientTestHelpers.CreateTestClient(HandleRequest);
+ var invoker = HttpClientCallInvokerFactory.Create(httpClient);
+ invoker.ReceiveMaxMessageSize = 1;
+
+ // Act
+ var call = invoker.AsyncDuplexStreamingCall(ClientTestHelpers.ServiceMethod, string.Empty, new CallOptions());
+ await call.RequestStream.WriteAsync(new HelloRequest
+ {
+ Name = "World"
+ });
+ await call.RequestStream.CompleteAsync();
+
+ // Assert
+ var ex = await ExceptionAssert.ThrowsAsync(() => call.ResponseStream.MoveNext(CancellationToken.None));
+ Assert.AreEqual(StatusCode.ResourceExhausted, ex.StatusCode);
+ Assert.AreEqual("Received message exceeds the maximum configured message size.", ex.Status.Detail);
+ }
+ }
+}