@@ -36,7 +36,7 @@ namespace Grpc.Net.Client
3636 /// Client objects can reuse the same channel. Creating a channel is an expensive operation compared to invoking
3737 /// a remote call so in general you should reuse a single channel for as many calls as possible.
3838 /// </summary>
39- public sealed class GrpcChannel : ChannelBase
39+ public sealed class GrpcChannel : ChannelBase , IDisposable
4040 {
4141 internal const int DefaultMaxReceiveMessageSize = 1024 * 1024 * 4 ; // 4 MB
4242
@@ -49,13 +49,21 @@ public sealed class GrpcChannel : ChannelBase
4949 internal List < CallCredentials > ? CallCredentials { get ; }
5050 internal Dictionary < string , ICompressionProvider > CompressionProviders { get ; }
5151 internal string MessageAcceptEncoding { get ; }
52+ internal bool Disposed { get ; private set ; }
5253
5354 // Timing related options that are set in unit tests
5455 internal ISystemClock Clock = SystemClock . Instance ;
5556 internal bool DisableClientDeadlineTimer { get ; set ; }
5657
58+ private bool _shouldDisposeHttpClient ;
59+
5760 internal GrpcChannel ( Uri address , GrpcChannelOptions channelOptions ) : base ( address . Authority )
5861 {
62+ // Dispose the HttpClient if...
63+ // 1. No client was specified and so the channel created the HttpClient itself
64+ // 2. User has specified a client and set DisposeHttpClient to true
65+ _shouldDisposeHttpClient = channelOptions . HttpClient == null || channelOptions . DisposeHttpClient ;
66+
5967 Address = address ;
6068 HttpClient = channelOptions . HttpClient ?? new HttpClient ( ) ;
6169 SendMaxMessageSize = channelOptions . MaxSendMessageSize ;
@@ -117,6 +125,11 @@ private void ValidateChannelCredentials()
117125 /// <returns>A new <see cref="CallInvoker"/>.</returns>
118126 public override CallInvoker CreateCallInvoker ( )
119127 {
128+ if ( Disposed )
129+ {
130+ throw new ObjectDisposedException ( nameof ( GrpcChannel ) ) ;
131+ }
132+
120133 var invoker = new HttpClientCallInvoker ( this ) ;
121134
122135 return invoker ;
@@ -211,5 +224,23 @@ public static GrpcChannel ForAddress(Uri address, GrpcChannelOptions channelOpti
211224
212225 return new GrpcChannel ( address , channelOptions ) ;
213226 }
227+
228+ /// <summary>
229+ /// Releases the resources used by the <see cref="GrpcChannel"/> class.
230+ /// Clients created with the channel can't be used after the channel is disposed.
231+ /// </summary>
232+ public void Dispose ( )
233+ {
234+ if ( Disposed )
235+ {
236+ return ;
237+ }
238+
239+ if ( _shouldDisposeHttpClient )
240+ {
241+ HttpClient . Dispose ( ) ;
242+ }
243+ Disposed = true ;
244+ }
214245 }
215246}
0 commit comments