Merge pull request #18086 from chwarr/servercallcontext-userstate

Add UserState dictionary to C# ServerCallContext
reviewable/pr18094/r2^2
Jan Tattermusch 6 years ago committed by GitHub
commit a635255095
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      src/csharp/Grpc.Core.Api/ServerCallContext.cs
  2. 47
      src/csharp/Grpc.Core.Tests/Interceptors/ServerInterceptorTest.cs

@ -17,6 +17,7 @@
#endregion #endregion
using System; using System;
using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -27,6 +28,8 @@ namespace Grpc.Core
/// </summary> /// </summary>
public abstract class ServerCallContext public abstract class ServerCallContext
{ {
private Dictionary<object, object> userState;
/// <summary> /// <summary>
/// Creates a new instance of <c>ServerCallContext</c>. /// Creates a new instance of <c>ServerCallContext</c>.
/// </summary> /// </summary>
@ -113,6 +116,12 @@ namespace Grpc.Core
/// </summary> /// </summary>
public AuthContext AuthContext => AuthContextCore; public AuthContext AuthContext => AuthContextCore;
/// <summary>
/// Gets a dictionary that can be used by the various interceptors and handlers of this
/// call to store arbitrary state.
/// </summary>
public IDictionary<object, object> UserState => UserStateCore;
/// <summary>Provides implementation of a non-virtual public member.</summary> /// <summary>Provides implementation of a non-virtual public member.</summary>
protected abstract Task WriteResponseHeadersAsyncCore(Metadata responseHeaders); protected abstract Task WriteResponseHeadersAsyncCore(Metadata responseHeaders);
/// <summary>Provides implementation of a non-virtual public member.</summary> /// <summary>Provides implementation of a non-virtual public member.</summary>
@ -135,7 +144,20 @@ namespace Grpc.Core
protected abstract Status StatusCore { get; set; } protected abstract Status StatusCore { get; set; }
/// <summary>Provides implementation of a non-virtual public member.</summary> /// <summary>Provides implementation of a non-virtual public member.</summary>
protected abstract WriteOptions WriteOptionsCore { get; set; } protected abstract WriteOptions WriteOptionsCore { get; set; }
/// <summary>Provides implementation of a non-virtual public member.</summary> /// <summary>Provides implementation of a non-virtual public member.</summary>
protected abstract AuthContext AuthContextCore { get; } protected abstract AuthContext AuthContextCore { get; }
/// <summary>Provides implementation of a non-virtual public member.</summary>
protected virtual IDictionary<object, object> UserStateCore
{
get
{
if (userState == null)
{
userState = new Dictionary<object, object>();
}
return userState;
}
}
} }
} }

@ -77,6 +77,53 @@ namespace Grpc.Core.Interceptors.Tests
Assert.AreEqual("CB1B2B3A", stringBuilder.ToString()); Assert.AreEqual("CB1B2B3A", stringBuilder.ToString());
} }
[Test]
public void UserStateVisibleToAllInterceptors()
{
object key1 = new object();
object value1 = new object();
const string key2 = "Interceptor #2";
const string value2 = "Important state";
var interceptor1 = new ServerCallContextInterceptor(ctx => {
// state starts off empty
Assert.AreEqual(0, ctx.UserState.Count);
ctx.UserState.Add(key1, value1);
});
var interceptor2 = new ServerCallContextInterceptor(ctx => {
// second interceptor can see state set by the first
bool found = ctx.UserState.TryGetValue(key1, out object storedValue1);
Assert.IsTrue(found);
Assert.AreEqual(value1, storedValue1);
ctx.UserState.Add(key2, value2);
});
var helper = new MockServiceHelper(Host);
helper.UnaryHandler = new UnaryServerMethod<string, string>((request, context) => {
// call handler can see all the state
bool found = context.UserState.TryGetValue(key1, out object storedValue1);
Assert.IsTrue(found);
Assert.AreEqual(value1, storedValue1);
found = context.UserState.TryGetValue(key2, out object storedValue2);
Assert.IsTrue(found);
Assert.AreEqual(value2, storedValue2);
return Task.FromResult("PASS");
});
helper.ServiceDefinition = helper.ServiceDefinition
.Intercept(interceptor2)
.Intercept(interceptor1);
var server = helper.GetServer();
server.Start();
var channel = helper.GetChannel();
Assert.AreEqual("PASS", Calls.BlockingUnaryCall(helper.CreateUnaryCall(), ""));
}
[Test] [Test]
public void CheckNullInterceptorRegistrationFails() public void CheckNullInterceptorRegistrationFails()
{ {

Loading…
Cancel
Save