public abstract class BidirectionalStreamingBase<TRequest, TResponse> : IDisposable
Base class for bidirectional streaming RPC methods. This wraps an underlying call returned by gRPC,
in order to provide a wrapper for the async response stream, allowing users to take advantage
of
await foreach
support from C# 8 onwards. Additionally, it wraps the
request stream in a buffer, allowing multiple requests to be written without waiting for them
to be transmitted.
To avoid memory leaks, users must dispose of gRPC streams.
Additionally, you are strongly advised to read the whole response stream, even if the data
is not required - this avoids effectively cancelling the call.
Properties
GrpcCall
public virtual AsyncDuplexStreamingCall<TRequest, TResponse> GrpcCall { get; }
Disposes of the underlying gRPC call. There is no need to dispose of both the wrapper
and the underlying call; it's typically simpler to dispose of the wrapper with a
using
statement as the wrapper is returned by client libraries.
Remarks
The default implementation just calls Dispose on the result of GrpcCall.
GetResponseStream()
public virtual AsyncResponseStream<TResponse> GetResponseStream()
Async stream to read streaming responses, exposed as an async sequence.
The default implementation will use GrpcCall to extract a response
stream, and adapt it to AsyncResponseStream<TResponse>.
If this method is called more than once, all the returned enumerators will be enumerating over the
same underlying response stream, which may cause confusion. Additionally, the sequence returned by
this method can only be iterated over a single time. Attempting to iterate more than once will cause
an InvalidOperationException.
TryWriteAsync(TRequest)
public virtual Task TryWriteAsync(TRequest message)
Writes a message to the stream, if there is enough space in the buffer and WriteCompleteAsync()
hasn't already been called. The same write options will be used as for the previous message.
null if the message queue is full or the stream has already been completed;
otherwise, a Task which will complete when the message has been written to the stream.
TryWriteAsync(TRequest, WriteOptions)
public virtual Task TryWriteAsync(TRequest message, WriteOptions options)
Writes a message to the stream, if there is enough space in the buffer and WriteCompleteAsync()
hasn't already been called.
null if the message queue is full or the stream has already been completed.
TryWriteCompleteAsync()
public virtual Task TryWriteCompleteAsync()
Completes the stream when all buffered messages have been sent.
Only the first call to this method on any instance will have any effect;
subsequent calls will return null.
A Task which will complete when the stream has finished being completed;
or null if this method has already been called.
WriteAsync(TRequest)
public virtual Task WriteAsync(TRequest message)
Writes a message to the stream, if there is enough space in the buffer and WriteCompleteAsync()
hasn't already been called. The same write options will be used as for the previous message.
There isn't enough space left in the buffer,
or WriteCompleteAsync() has already been called.
WriteCompleteAsync()
public virtual Task WriteCompleteAsync()
Completes the stream when all buffered messages have been sent. This method can only be called
once, and further messages cannot be written after it has been called.
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Hard to understand","hardToUnderstand","thumb-down"],["Incorrect information or sample code","incorrectInformationOrSampleCode","thumb-down"],["Missing the information/samples I need","missingTheInformationSamplesINeed","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-09-03 UTC."],[[["\u003cp\u003eThe \u003ccode\u003eBidirectionalStreamingBase<TRequest, TResponse>\u003c/code\u003e class is a base for bidirectional streaming RPC methods, wrapping a gRPC call to provide an async response stream and a buffered request stream.\u003c/p\u003e\n"],["\u003cp\u003eIt supports \u003ccode\u003eawait foreach\u003c/code\u003e from C# 8 onwards, allowing users to handle async response streams efficiently, and buffers requests for multiple writes without waiting for transmission.\u003c/p\u003e\n"],["\u003cp\u003eThis class implements \u003ccode\u003eIDisposable\u003c/code\u003e, requiring users to dispose of gRPC streams to avoid memory leaks, and it is strongly advised to read the entire response stream.\u003c/p\u003e\n"],["\u003cp\u003eIt offers methods such as \u003ccode\u003eTryWriteAsync\u003c/code\u003e and \u003ccode\u003eWriteAsync\u003c/code\u003e for writing messages to the stream, along with \u003ccode\u003eTryWriteCompleteAsync\u003c/code\u003e and \u003ccode\u003eWriteCompleteAsync\u003c/code\u003e to signal the completion of the stream.\u003c/p\u003e\n"],["\u003cp\u003eThe latest version of the API is version 4.10.0, with links to older versions going back to 3.2.0 all available on the page.\u003c/p\u003e\n"]]],[],null,["# Class BidirectionalStreamingBase<TRequest, TResponse> (4.10.0)\n\nVersion latestkeyboard_arrow_down\n\n- [4.10.0 (latest)](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2)\n- [4.8.0](/dotnet/docs/reference/Google.Api.Gax/4.8.0/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2)\n- [4.4.0](/dotnet/docs/reference/Google.Api.Gax/4.4.0/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2)\n- [4.3.1](/dotnet/docs/reference/Google.Api.Gax/4.3.1/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2)\n- [4.2.0](/dotnet/docs/reference/Google.Api.Gax/4.2.0/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2)\n- [4.0.0](/dotnet/docs/reference/Google.Api.Gax/4.0.0/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2)\n- [3.2.0](/dotnet/docs/reference/Google.Api.Gax/3.2.0/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2) \n\n public abstract class BidirectionalStreamingBase\u003cTRequest, TResponse\u003e : IDisposable\n\nBase class for bidirectional streaming RPC methods. This wraps an underlying call returned by gRPC,\nin order to provide a wrapper for the async response stream, allowing users to take advantage\nof \n\n await foreach\n\nsupport from C# 8 onwards. Additionally, it wraps the request stream in a buffer, allowing multiple requests to be written without waiting for them to be transmitted.\n\n\u003cbr /\u003e\n\nInheritance\n-----------\n\n[object](https://learn.microsoft.com/dotnet/api/system.object) \\\u003e BidirectionalStreamingBase\\\u003cTRequest, TResponse\\\u003e \n\nImplements\n----------\n\n[IDisposable](https://learn.microsoft.com/dotnet/api/system.idisposable) \n\nInherited Members\n-----------------\n\n[object.Equals(object)](https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)) \n[object.Equals(object, object)](https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)) \n[object.GetHashCode()](https://learn.microsoft.com/dotnet/api/system.object.gethashcode) \n[object.GetType()](https://learn.microsoft.com/dotnet/api/system.object.gettype) \n[object.MemberwiseClone()](https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone) \n[object.ReferenceEquals(object, object)](https://learn.microsoft.com/dotnet/api/system.object.referenceequals) \n[object.ToString()](https://learn.microsoft.com/dotnet/api/system.object.tostring)\n\nNamespace\n---------\n\n[Google.Api.Gax.Grpc](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc)\n\nAssembly\n--------\n\nGoogle.Api.Gax.Grpc.dll\n\nRemarks\n-------\n\nTo avoid memory leaks, users must dispose of gRPC streams.\nAdditionally, you are strongly advised to read the whole response stream, even if the data\nis not required - this avoids effectively cancelling the call.\n\nProperties\n----------\n\n### GrpcCall\n\n public virtual AsyncDuplexStreamingCall\u003cTRequest, TResponse\u003e GrpcCall { get; }\n\nThe underlying gRPC duplex streaming call.\nWarning: DO NOT USE `GrpcCall.RequestStream` at all if using\n[TryWriteAsync(TRequest)](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_TryWriteAsync__0_), [WriteAsync(TRequest)](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_WriteAsync__0_),\n[TryWriteAsync(TRequest, WriteOptions)](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_TryWriteAsync__0_Grpc_Core_WriteOptions_) , or [WriteAsync(TRequest, WriteOptions)](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_WriteAsync__0_Grpc_Core_WriteOptions_).\nDoing so will cause conflict with the write-buffer used within the `[Try]WriteAsync` methods.\n\nMethods\n-------\n\n### Dispose()\n\n public virtual void Dispose()\n\nDisposes of the underlying gRPC call. There is no need to dispose of both the wrapper\nand the underlying call; it's typically simpler to dispose of the wrapper with a \n\n using\n\nstatement as the wrapper is returned by client libraries.\n**Remarks** \nThe default implementation just calls Dispose on the result of [GrpcCall](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_GrpcCall).\n\n### GetResponseStream()\n\n public virtual AsyncResponseStream\u003cTResponse\u003e GetResponseStream()\n\nAsync stream to read streaming responses, exposed as an async sequence.\nThe default implementation will use [GrpcCall](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_GrpcCall) to extract a response\nstream, and adapt it to [AsyncResponseStream\\\u003cTResponse\\\u003e](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.AsyncResponseStream-1).\n\n**Remarks** \nIf this method is called more than once, all the returned enumerators will be enumerating over the\nsame underlying response stream, which may cause confusion. Additionally, the sequence returned by\nthis method can only be iterated over a single time. Attempting to iterate more than once will cause\nan [InvalidOperationException](https://learn.microsoft.com/dotnet/api/system.invalidoperationexception).\n\n### TryWriteAsync(TRequest)\n\n public virtual Task TryWriteAsync(TRequest message)\n\nWrites a message to the stream, if there is enough space in the buffer and [WriteCompleteAsync()](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_WriteCompleteAsync)\nhasn't already been called. The same write options will be used as for the previous message.\n\n### TryWriteAsync(TRequest, WriteOptions)\n\n public virtual Task TryWriteAsync(TRequest message, WriteOptions options)\n\nWrites a message to the stream, if there is enough space in the buffer and [WriteCompleteAsync()](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_WriteCompleteAsync)\nhasn't already been called.\n\n### TryWriteCompleteAsync()\n\n public virtual Task TryWriteCompleteAsync()\n\nCompletes the stream when all buffered messages have been sent.\nOnly the first call to this method on any instance will have any effect;\nsubsequent calls will return `null`.\n\n### WriteAsync(TRequest)\n\n public virtual Task WriteAsync(TRequest message)\n\nWrites a message to the stream, if there is enough space in the buffer and [WriteCompleteAsync()](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_WriteCompleteAsync)\nhasn't already been called. The same write options will be used as for the previous message.\n\n### WriteAsync(TRequest, WriteOptions)\n\n public virtual Task WriteAsync(TRequest message, WriteOptions options)\n\nWrites a message to the stream, if there is enough space in the buffer and [WriteCompleteAsync()](/dotnet/docs/reference/Google.Api.Gax/latest/Google.Api.Gax.Grpc.BidirectionalStreamingBase-2#Google_Api_Gax_Grpc_BidirectionalStreamingBase_2_WriteCompleteAsync)\nhasn't already been called.\n\n### WriteCompleteAsync()\n\n public virtual Task WriteCompleteAsync()\n\nCompletes the stream when all buffered messages have been sent. This method can only be called\nonce, and further messages cannot be written after it has been called."]]