aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/csharp
diff options
context:
space:
mode:
Diffstat (limited to 'src/csharp')
-rw-r--r--src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs37
-rw-r--r--src/csharp/Grpc.Core.Tests/FakeCredentials.cs10
-rwxr-xr-xsrc/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj4
-rw-r--r--src/csharp/Grpc.Core.Tests/MetadataTest.cs2
-rw-r--r--src/csharp/Grpc.Core.Tests/SanityTest.cs6
-rw-r--r--src/csharp/Grpc.Core/Channel.cs2
-rw-r--r--src/csharp/Grpc.Core/ChannelCredentials.cs39
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCall.cs29
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallBase.cs32
-rw-r--r--src/csharp/Grpc.Core/Internal/AsyncCallServer.cs10
-rw-r--r--src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs4
-rw-r--r--src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs2
-rw-r--r--src/csharp/Grpc.Core/Metadata.cs4
-rwxr-xr-xsrc/csharp/Grpc.Core/Version.csproj.include2
-rw-r--r--src/csharp/Grpc.Core/VersionInfo.cs4
-rwxr-xr-xsrc/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj4
-rwxr-xr-xsrc/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj4
-rwxr-xr-xsrc/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj4
-rwxr-xr-xsrc/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj4
-rwxr-xr-xsrc/csharp/build_packages_dotnetcli.bat2
-rw-r--r--src/csharp/build_unitypackage.bat2
22 files changed, 149 insertions, 60 deletions
diff --git a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
index 62cc904a61..843d88bfb6 100644
--- a/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
+++ b/src/csharp/Grpc.Core.Tests/ChannelCredentialsTest.cs
@@ -17,13 +17,7 @@
#endregion
using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core;
using Grpc.Core.Internal;
-using Grpc.Core.Utils;
using NUnit.Framework;
namespace Grpc.Core.Tests
@@ -44,9 +38,38 @@ namespace Grpc.Core.Tests
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(null, new FakeCallCredentials()));
Assert.Throws(typeof(ArgumentNullException), () => ChannelCredentials.Create(new FakeChannelCredentials(true), null));
-
+
// forbid composing non-composable
Assert.Throws(typeof(ArgumentException), () => ChannelCredentials.Create(new FakeChannelCredentials(false), new FakeCallCredentials()));
}
+
+ [Test]
+ public void ChannelCredentials_NativeCredentialsAreReused()
+ {
+ // always returning the same native object is critical for subchannel sharing to work with secure channels
+ var creds = new SslCredentials();
+ var nativeCreds1 = creds.GetNativeCredentials();
+ var nativeCreds2 = creds.GetNativeCredentials();
+ Assert.AreSame(nativeCreds1, nativeCreds2);
+ }
+
+ [Test]
+ public void ChannelCredentials_CreateExceptionIsCached()
+ {
+ var creds = new ChannelCredentialsWithCreateNativeThrows();
+ var ex1 = Assert.Throws(typeof(Exception), () => creds.GetNativeCredentials());
+ var ex2 = Assert.Throws(typeof(Exception), () => creds.GetNativeCredentials());
+ Assert.AreSame(ex1, ex2);
+ }
+
+ internal class ChannelCredentialsWithCreateNativeThrows : ChannelCredentials
+ {
+ internal override bool IsComposable => false;
+
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
+ {
+ throw new Exception("Creation of native credentials has failed on purpose.");
+ }
+ }
}
}
diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
index 7d658576e5..f23c9e9757 100644
--- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
+++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
@@ -16,15 +16,7 @@
#endregion
-using System;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
-using System.Threading.Tasks;
-using Grpc.Core;
using Grpc.Core.Internal;
-using Grpc.Core.Utils;
-using NUnit.Framework;
namespace Grpc.Core.Tests
{
@@ -42,7 +34,7 @@ namespace Grpc.Core.Tests
get { return composable; }
}
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return null;
}
diff --git a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
index 18993a93e0..d58f046824 100755
--- a/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
+++ b/src/csharp/Grpc.Core.Tests/Grpc.Core.Tests.csproj
@@ -17,8 +17,8 @@
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
- <PackageReference Include="NUnit" Version="3.6.0" />
- <PackageReference Include="NUnitLite" Version="3.6.0" />
+ <PackageReference Include="NUnit" Version="3.10.1" />
+ <PackageReference Include="NUnitLite" Version="3.10.1" />
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="ReportGenerator" Version="2.4.4.0" />
</ItemGroup>
diff --git a/src/csharp/Grpc.Core.Tests/MetadataTest.cs b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
index 8916731757..171c5c470e 100644
--- a/src/csharp/Grpc.Core.Tests/MetadataTest.cs
+++ b/src/csharp/Grpc.Core.Tests/MetadataTest.cs
@@ -66,6 +66,8 @@ namespace Grpc.Core.Tests
new Metadata.Entry("0123456789abc", "XYZ");
new Metadata.Entry("-abc", "XYZ");
new Metadata.Entry("a_bc_", "XYZ");
+ new Metadata.Entry("abc.xyz", "XYZ");
+ new Metadata.Entry("abc.xyz-bin", new byte[] {1, 2, 3});
Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc[", "xyz"));
Assert.Throws(typeof(ArgumentException), () => new Metadata.Entry("abc/", "xyz"));
}
diff --git a/src/csharp/Grpc.Core.Tests/SanityTest.cs b/src/csharp/Grpc.Core.Tests/SanityTest.cs
index 73efad1f84..eaad409ec0 100644
--- a/src/csharp/Grpc.Core.Tests/SanityTest.cs
+++ b/src/csharp/Grpc.Core.Tests/SanityTest.cs
@@ -65,13 +65,13 @@ namespace Grpc.Core.Tests
{
foreach (var m in t.GetMethods())
{
- var attributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true);
- if (attributes.Length > 0)
+ var testAttributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestAttribute), true);
+ var testCaseAttributes = m.GetCustomAttributes(typeof(NUnit.Framework.TestCaseAttribute), true);
+ if (testAttributes.Length > 0 || testCaseAttributes.Length > 0)
{
testClasses.Add(t.FullName);
break;
}
-
}
}
testClasses.Sort();
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index e9930b6fbc..7912b06b71 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -72,9 +72,9 @@ namespace Grpc.Core
this.environment = GrpcEnvironment.AddRef();
this.completionQueue = this.environment.PickCompletionQueue();
- using (var nativeCredentials = credentials.ToNativeCredentials())
using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options.Values))
{
+ var nativeCredentials = credentials.GetNativeCredentials();
if (nativeCredentials != null)
{
this.handle = ChannelSafeHandle.CreateSecure(nativeCredentials, target, nativeChannelArgs);
diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs
index ba482897d7..3ce32f31b7 100644
--- a/src/csharp/Grpc.Core/ChannelCredentials.cs
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -31,6 +31,19 @@ namespace Grpc.Core
public abstract class ChannelCredentials
{
static readonly ChannelCredentials InsecureInstance = new InsecureCredentialsImpl();
+ readonly Lazy<ChannelCredentialsSafeHandle> cachedNativeCredentials;
+
+ /// <summary>
+ /// Creates a new instance of channel credentials
+ /// </summary>
+ public ChannelCredentials()
+ {
+ // Native credentials object need to be kept alive once initialized for subchannel sharing to work correctly
+ // with secure connections. See https://github.com/grpc/grpc/issues/15207.
+ // We rely on finalizer to clean up the native portion of ChannelCredentialsSafeHandle after the ChannelCredentials
+ // instance becomes unused.
+ this.cachedNativeCredentials = new Lazy<ChannelCredentialsSafeHandle>(() => CreateNativeCredentials());
+ }
/// <summary>
/// Returns instance of credentials that provides no security and
@@ -57,11 +70,22 @@ namespace Grpc.Core
}
/// <summary>
- /// Creates native object for the credentials. May return null if insecure channel
- /// should be created.
+ /// Gets native object for the credentials, creating one if it already doesn't exist. May return null if insecure channel
+ /// should be created. Caller must not call <c>Dispose()</c> on the returned native credentials as their lifetime
+ /// is managed by this class (and instances of native credentials are cached).
+ /// </summary>
+ /// <returns>The native credentials.</returns>
+ internal ChannelCredentialsSafeHandle GetNativeCredentials()
+ {
+ return cachedNativeCredentials.Value;
+ }
+
+ /// <summary>
+ /// Creates a new native object for the credentials. May return null if insecure channel
+ /// should be created. For internal use only, use <see cref="GetNativeCredentials"/> instead.
/// </summary>
/// <returns>The native credentials.</returns>
- internal abstract ChannelCredentialsSafeHandle ToNativeCredentials();
+ internal abstract ChannelCredentialsSafeHandle CreateNativeCredentials();
/// <summary>
/// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>.
@@ -73,7 +97,7 @@ namespace Grpc.Core
private sealed class InsecureCredentialsImpl : ChannelCredentials
{
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return null;
}
@@ -145,7 +169,7 @@ namespace Grpc.Core
get { return true; }
}
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
}
@@ -173,12 +197,11 @@ namespace Grpc.Core
GrpcPreconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
}
- internal override ChannelCredentialsSafeHandle ToNativeCredentials()
+ internal override ChannelCredentialsSafeHandle CreateNativeCredentials()
{
- using (var channelCreds = channelCredentials.ToNativeCredentials())
using (var callCreds = callCredentials.ToNativeCredentials())
{
- var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCreds, callCreds);
+ var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCredentials.GetNativeCredentials(), callCreds);
if (nativeComposite.IsInvalid)
{
throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCall.cs b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
index 9946d1a6cf..66902f3caa 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCall.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCall.cs
@@ -108,7 +108,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while invoking completion delegate.");
+ Logger.Error(e, "Exception occurred while invoking completion delegate.");
}
}
finally
@@ -325,9 +325,18 @@ namespace Grpc.Core.Internal
}
}
- protected override void OnAfterReleaseResources()
+ protected override void OnAfterReleaseResourcesLocked()
{
details.Channel.RemoveCallReference(this);
+ }
+
+ protected override void OnAfterReleaseResourcesUnlocked()
+ {
+ // If cancellation callback is in progress, this can block
+ // so we need to do this outside of call's lock to prevent
+ // deadlock.
+ // See https://github.com/grpc/grpc/issues/14777
+ // See https://github.com/dotnet/corefx/issues/14903
cancellationTokenRegistration?.Dispose();
}
@@ -448,6 +457,7 @@ namespace Grpc.Core.Internal
TResponse msg = default(TResponse);
var deserializeException = TryDeserialize(receivedMessage, out msg);
+ bool releasedResources;
lock (myLock)
{
finished = true;
@@ -464,7 +474,12 @@ namespace Grpc.Core.Internal
streamingWriteTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
responseHeadersTcs.SetResult(responseHeaders);
@@ -494,6 +509,7 @@ namespace Grpc.Core.Internal
TaskCompletionSource<object> delayedStreamingWriteTcs = null;
+ bool releasedResources;
lock (myLock)
{
finished = true;
@@ -504,7 +520,12 @@ namespace Grpc.Core.Internal
streamingWriteTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (delayedStreamingWriteTcs != null)
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
index 3273c26b88..5a53049e4b 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallBase.cs
@@ -196,10 +196,14 @@ namespace Grpc.Core.Internal
call.Dispose();
}
disposed = true;
- OnAfterReleaseResources();
+ OnAfterReleaseResourcesLocked();
}
- protected virtual void OnAfterReleaseResources()
+ protected virtual void OnAfterReleaseResourcesLocked()
+ {
+ }
+
+ protected virtual void OnAfterReleaseResourcesUnlocked()
{
}
@@ -235,6 +239,7 @@ namespace Grpc.Core.Internal
{
bool delayCompletion = false;
TaskCompletionSource<object> origTcs = null;
+ bool releasedResources;
lock (myLock)
{
if (!success && !finished && IsClient) {
@@ -252,7 +257,12 @@ namespace Grpc.Core.Internal
streamingWriteTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (!success)
@@ -282,9 +292,15 @@ namespace Grpc.Core.Internal
/// </summary>
protected void HandleSendStatusFromServerFinished(bool success)
{
+ bool releasedResources;
lock (myLock)
{
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (!success)
@@ -310,6 +326,7 @@ namespace Grpc.Core.Internal
var deserializeException = (success && receivedMessage != null) ? TryDeserialize(receivedMessage, out msg) : null;
TaskCompletionSource<TRead> origTcs = null;
+ bool releasedResources;
lock (myLock)
{
origTcs = streamingReadTcs;
@@ -332,7 +349,12 @@ namespace Grpc.Core.Internal
streamingReadTcs = null;
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (deserializeException != null && !IsClient)
diff --git a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
index 11acb27533..0ceca4abb8 100644
--- a/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
+++ b/src/csharp/Grpc.Core/Internal/AsyncCallServer.cs
@@ -184,7 +184,7 @@ namespace Grpc.Core.Internal
throw new InvalidOperationException("Call be only called for client calls");
}
- protected override void OnAfterReleaseResources()
+ protected override void OnAfterReleaseResourcesLocked()
{
server.RemoveCallReference(this);
}
@@ -206,6 +206,7 @@ namespace Grpc.Core.Internal
{
// NOTE: because this event is a result of batch containing GRPC_OP_RECV_CLOSE_ON_SERVER,
// success will be always set to true.
+ bool releasedResources;
lock (myLock)
{
finished = true;
@@ -217,7 +218,12 @@ namespace Grpc.Core.Internal
streamingReadTcs = new TaskCompletionSource<TRequest>();
streamingReadTcs.SetResult(default(TRequest));
}
- ReleaseResourcesIfPossible();
+ releasedResources = ReleaseResourcesIfPossible();
+ }
+
+ if (releasedResources)
+ {
+ OnAfterReleaseResourcesUnlocked();
}
if (cancelled)
diff --git a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
index 53a859d18f..085e7faf59 100644
--- a/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/BatchContextSafeHandle.cs
@@ -144,7 +144,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while invoking batch completion delegate.");
+ Logger.Error(e, "Exception occurred while invoking batch completion delegate.");
}
finally
{
diff --git a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
index 8ddda9be5c..622cfde9e7 100644
--- a/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
+++ b/src/csharp/Grpc.Core/Internal/GrpcThreadPool.cs
@@ -189,7 +189,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while extracting event from completion registry.");
+ Logger.Error(e, "Exception occurred while extracting event from completion registry.");
}
}
}
@@ -233,7 +233,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while invoking completion delegate");
+ Logger.Error(e, "Exception occurred while invoking completion delegate");
}
finally
{
diff --git a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
index ebc2d6d8d6..24fde75e5a 100644
--- a/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/RequestCallContextSafeHandle.cs
@@ -112,7 +112,7 @@ namespace Grpc.Core.Internal
}
catch (Exception e)
{
- Logger.Error(e, "Exception occured while invoking request call completion delegate.");
+ Logger.Error(e, "Exception occurred while invoking request call completion delegate.");
}
finally
{
diff --git a/src/csharp/Grpc.Core/Metadata.cs b/src/csharp/Grpc.Core/Metadata.cs
index 0e4456278c..281952d6d4 100644
--- a/src/csharp/Grpc.Core/Metadata.cs
+++ b/src/csharp/Grpc.Core/Metadata.cs
@@ -225,7 +225,7 @@ namespace Grpc.Core
/// </summary>
public class Entry
{
- private static readonly Regex ValidKeyRegex = new Regex("^[a-z0-9_-]+$");
+ private static readonly Regex ValidKeyRegex = new Regex("^[.a-z0-9_-]+$");
readonly string key;
readonly string value;
@@ -360,7 +360,7 @@ namespace Grpc.Core
{
var normalized = GrpcPreconditions.CheckNotNull(key, "key").ToLowerInvariant();
GrpcPreconditions.CheckArgument(ValidKeyRegex.IsMatch(normalized),
- "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores and hyphens.");
+ "Metadata entry key not valid. Keys can only contain lowercase alphanumeric characters, underscores, hyphens and dots.");
return normalized;
}
diff --git a/src/csharp/Grpc.Core/Version.csproj.include b/src/csharp/Grpc.Core/Version.csproj.include
index 45bd8ebd85..18515ea1e8 100755
--- a/src/csharp/Grpc.Core/Version.csproj.include
+++ b/src/csharp/Grpc.Core/Version.csproj.include
@@ -1,7 +1,7 @@
<!-- This file is generated -->
<Project>
<PropertyGroup>
- <GrpcCsharpVersion>1.15.0-dev</GrpcCsharpVersion>
+ <GrpcCsharpVersion>1.16.0-dev</GrpcCsharpVersion>
<GoogleProtobufVersion>3.6.1</GoogleProtobufVersion>
</PropertyGroup>
</Project>
diff --git a/src/csharp/Grpc.Core/VersionInfo.cs b/src/csharp/Grpc.Core/VersionInfo.cs
index 295e0f2577..55d09dda7a 100644
--- a/src/csharp/Grpc.Core/VersionInfo.cs
+++ b/src/csharp/Grpc.Core/VersionInfo.cs
@@ -33,11 +33,11 @@ namespace Grpc.Core
/// <summary>
/// Current <c>AssemblyFileVersion</c> of gRPC C# assemblies
/// </summary>
- public const string CurrentAssemblyFileVersion = "1.15.0.0";
+ public const string CurrentAssemblyFileVersion = "1.16.0.0";
/// <summary>
/// Current version of gRPC C#
/// </summary>
- public const string CurrentVersion = "1.15.0-dev";
+ public const string CurrentVersion = "1.16.0-dev";
}
}
diff --git a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
index d2cc5bbc65..7493eb8051 100755
--- a/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
+++ b/src/csharp/Grpc.Examples.Tests/Grpc.Examples.Tests.csproj
@@ -17,8 +17,8 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="NUnit" Version="3.6.0" />
- <PackageReference Include="NUnitLite" Version="3.6.0" />
+ <PackageReference Include="NUnit" Version="3.10.1" />
+ <PackageReference Include="NUnitLite" Version="3.10.1" />
<PackageReference Include="Moq" Version="4.8.2" />
</ItemGroup>
diff --git a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
index 9da0539dcb..616e56df10 100755
--- a/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
+++ b/src/csharp/Grpc.HealthCheck.Tests/Grpc.HealthCheck.Tests.csproj
@@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="NUnit" Version="3.6.0" />
- <PackageReference Include="NUnitLite" Version="3.6.0" />
+ <PackageReference Include="NUnit" Version="3.10.1" />
+ <PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
diff --git a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
index e4f36d8810..ad7033b782 100755
--- a/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
+++ b/src/csharp/Grpc.IntegrationTesting/Grpc.IntegrationTesting.csproj
@@ -19,8 +19,8 @@
<ItemGroup>
<PackageReference Include="Google.Protobuf" Version="$(GoogleProtobufVersion)" />
<PackageReference Include="CommandLineParser" Version="2.1.1-beta" />
- <PackageReference Include="NUnit" Version="3.6.0" />
- <PackageReference Include="NUnitLite" Version="3.6.0" />
+ <PackageReference Include="NUnit" Version="3.10.1" />
+ <PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
diff --git a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
index d368697124..0c12f38f25 100755
--- a/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
+++ b/src/csharp/Grpc.Reflection.Tests/Grpc.Reflection.Tests.csproj
@@ -16,8 +16,8 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="NUnit" Version="3.6.0" />
- <PackageReference Include="NUnitLite" Version="3.6.0" />
+ <PackageReference Include="NUnit" Version="3.10.1" />
+ <PackageReference Include="NUnitLite" Version="3.10.1" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
diff --git a/src/csharp/build_packages_dotnetcli.bat b/src/csharp/build_packages_dotnetcli.bat
index 8f38f0aa20..24d016104c 100755
--- a/src/csharp/build_packages_dotnetcli.bat
+++ b/src/csharp/build_packages_dotnetcli.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.15.0-dev
+set VERSION=1.16.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe
diff --git a/src/csharp/build_unitypackage.bat b/src/csharp/build_unitypackage.bat
index 9c53114b84..4e7ac4e414 100644
--- a/src/csharp/build_unitypackage.bat
+++ b/src/csharp/build_unitypackage.bat
@@ -13,7 +13,7 @@
@rem limitations under the License.
@rem Current package versions
-set VERSION=1.15.0-dev
+set VERSION=1.16.0-dev
@rem Adjust the location of nuget.exe
set NUGET=C:\nuget\nuget.exe