refactor ServerServiceDefinition and move to Grpc.Core.Api

pull/17889/head
Jan Tattermusch 6 years ago
parent 906c12568e
commit c4e59973a2
  1. 41
      src/csharp/Grpc.Core.Api/ServerServiceDefinition.cs
  2. 3
      src/csharp/Grpc.Core.Api/ServiceBinderBase.cs
  3. 3
      src/csharp/Grpc.Core/ForwardedTypes.cs
  4. 2
      src/csharp/Grpc.Core/Interceptors/ServerServiceDefinitionExtensions.cs
  5. 78
      src/csharp/Grpc.Core/Internal/ServerServiceDefinitionExtensions.cs
  6. 2
      src/csharp/Grpc.Core/Server.cs

@ -18,33 +18,31 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Grpc.Core.Interceptors;
using Grpc.Core.Internal;
using Grpc.Core.Utils;
namespace Grpc.Core namespace Grpc.Core
{ {
/// <summary> /// <summary>
/// Mapping of method names to server call handlers. /// Stores mapping of methods to server call handlers.
/// Normally, the <c>ServerServiceDefinition</c> objects will be created by the <c>BindService</c> factory method /// Normally, the <c>ServerServiceDefinition</c> objects will be created by the <c>BindService</c> factory method
/// that is part of the autogenerated code for a protocol buffers service definition. /// that is part of the autogenerated code for a protocol buffers service definition.
/// </summary> /// </summary>
public class ServerServiceDefinition public class ServerServiceDefinition
{ {
readonly ReadOnlyDictionary<string, IServerCallHandler> callHandlers; readonly IReadOnlyList<Action<ServiceBinderBase>> addMethodActions;
internal ServerServiceDefinition(Dictionary<string, IServerCallHandler> callHandlers) internal ServerServiceDefinition(List<Action<ServiceBinderBase>> addMethodActions)
{ {
this.callHandlers = new ReadOnlyDictionary<string, IServerCallHandler>(callHandlers); this.addMethodActions = addMethodActions.AsReadOnly();
} }
internal IDictionary<string, IServerCallHandler> CallHandlers /// <summary>
/// Forwards all the previously stored <c>AddMethod</c> calls to the service binder.
/// </summary>
internal void BindService(ServiceBinderBase serviceBinder)
{ {
get foreach (var addMethodAction in addMethodActions)
{ {
return this.callHandlers; addMethodAction(serviceBinder);
} }
} }
@ -62,7 +60,10 @@ namespace Grpc.Core
/// </summary> /// </summary>
public class Builder public class Builder
{ {
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>(); // to maintain legacy behavior, we need to detect duplicate keys and throw the same exception as before
readonly Dictionary<string, object> duplicateDetector = new Dictionary<string, object>();
// for each AddMethod call, we store an action that will later register the method and handler with ServiceBinderBase
readonly List<Action<ServiceBinderBase>> addMethodActions = new List<Action<ServiceBinderBase>>();
/// <summary> /// <summary>
/// Creates a new instance of builder. /// Creates a new instance of builder.
@ -85,7 +86,8 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler)); duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this; return this;
} }
@ -103,7 +105,8 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler)); duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this; return this;
} }
@ -121,7 +124,8 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler)); duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this; return this;
} }
@ -139,7 +143,8 @@ namespace Grpc.Core
where TRequest : class where TRequest : class
where TResponse : class where TResponse : class
{ {
callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler)); duplicateDetector.Add(method.FullName, null);
addMethodActions.Add((serviceBinder) => serviceBinder.AddMethod(method, handler));
return this; return this;
} }
@ -149,7 +154,7 @@ namespace Grpc.Core
/// <returns>The <c>ServerServiceDefinition</c> object.</returns> /// <returns>The <c>ServerServiceDefinition</c> object.</returns>
public ServerServiceDefinition Build() public ServerServiceDefinition Build()
{ {
return new ServerServiceDefinition(callHandlers); return new ServerServiceDefinition(addMethodActions);
} }
} }
} }

@ -20,8 +20,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Grpc.Core.Interceptors;
using Grpc.Core.Internal;
using Grpc.Core.Utils; using Grpc.Core.Utils;
namespace Grpc.Core namespace Grpc.Core
@ -30,7 +28,6 @@ namespace Grpc.Core
/// Allows binding server-side method implementations in alternative serving stacks. /// Allows binding server-side method implementations in alternative serving stacks.
/// Instances of this class are usually populated by the <c>BindService</c> method /// Instances of this class are usually populated by the <c>BindService</c> method
/// that is part of the autogenerated code for a protocol buffers service definition. /// that is part of the autogenerated code for a protocol buffers service definition.
/// <seealso cref="ServerServiceDefinition"/>
/// </summary> /// </summary>
public class ServiceBinderBase public class ServiceBinderBase
{ {

@ -25,7 +25,6 @@ using Grpc.Core.Utils;
// https://docs.microsoft.com/en-us/dotnet/framework/app-domains/type-forwarding-in-the-common-language-runtime // https://docs.microsoft.com/en-us/dotnet/framework/app-domains/type-forwarding-in-the-common-language-runtime
// TODO(jtattermusch): move types needed for implementing a client // TODO(jtattermusch): move types needed for implementing a client
// TODO(jtattermusch): ServerServiceDefinition depends on IServerCallHandler (which depends on other stuff)
[assembly:TypeForwardedToAttribute(typeof(ILogger))] [assembly:TypeForwardedToAttribute(typeof(ILogger))]
[assembly:TypeForwardedToAttribute(typeof(LogLevel))] [assembly:TypeForwardedToAttribute(typeof(LogLevel))]
@ -50,6 +49,8 @@ using Grpc.Core.Utils;
[assembly:TypeForwardedToAttribute(typeof(ClientStreamingServerMethod<,>))] [assembly:TypeForwardedToAttribute(typeof(ClientStreamingServerMethod<,>))]
[assembly:TypeForwardedToAttribute(typeof(ServerStreamingServerMethod<,>))] [assembly:TypeForwardedToAttribute(typeof(ServerStreamingServerMethod<,>))]
[assembly:TypeForwardedToAttribute(typeof(DuplexStreamingServerMethod<,>))] [assembly:TypeForwardedToAttribute(typeof(DuplexStreamingServerMethod<,>))]
[assembly:TypeForwardedToAttribute(typeof(ServerServiceDefinition))]
[assembly:TypeForwardedToAttribute(typeof(ServiceBinderBase))]
[assembly:TypeForwardedToAttribute(typeof(Status))] [assembly:TypeForwardedToAttribute(typeof(Status))]
[assembly:TypeForwardedToAttribute(typeof(StatusCode))] [assembly:TypeForwardedToAttribute(typeof(StatusCode))]
[assembly:TypeForwardedToAttribute(typeof(WriteOptions))] [assembly:TypeForwardedToAttribute(typeof(WriteOptions))]

@ -44,7 +44,7 @@ namespace Grpc.Core.Interceptors
{ {
GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition)); GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition));
GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor)); GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor));
return new ServerServiceDefinition(serverServiceDefinition.CallHandlers.ToDictionary(x => x.Key, x => x.Value.Intercept(interceptor))); return new ServerServiceDefinition(serverServiceDefinition.GetCallHandlers().ToDictionary(x => x.Key, x => x.Value.Intercept(interceptor)));
} }
/// <summary> /// <summary>

@ -0,0 +1,78 @@
#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.Collections.Generic;
using System.Collections.ObjectModel;
using Grpc.Core.Internal;
namespace Grpc.Core
{
internal static class ServerServiceDefinitionExtensions
{
/// <summary>
/// Maps methods from <c>ServerServiceDefinition</c> to server call handlers.
/// </summary>
internal static ReadOnlyDictionary<string, IServerCallHandler> GetCallHandlers(this ServerServiceDefinition serviceDefinition)
{
var binder = new DefaultServiceBinder();
serviceDefinition.BindService(binder);
return binder.GetCallHandlers();
}
/// <summary>
/// Helper for converting <c>ServerServiceDefinition</c> to server call handlers.
/// </summary>
private class DefaultServiceBinder : ServiceBinderBase
{
readonly Dictionary<string, IServerCallHandler> callHandlers = new Dictionary<string, IServerCallHandler>();
internal ReadOnlyDictionary<string, IServerCallHandler> GetCallHandlers()
{
return new ReadOnlyDictionary<string, IServerCallHandler>(this.callHandlers);
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
UnaryServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.UnaryCall(method, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
ClientStreamingServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.ClientStreamingCall(method, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
ServerStreamingServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.ServerStreamingCall(method, handler));
}
public override void AddMethod<TRequest, TResponse>(
Method<TRequest, TResponse> method,
DuplexStreamingServerMethod<TRequest, TResponse> handler)
{
callHandlers.Add(method.FullName, ServerCalls.DuplexStreamingCall(method, handler));
}
}
}
}

@ -257,7 +257,7 @@ namespace Grpc.Core
lock (myLock) lock (myLock)
{ {
GrpcPreconditions.CheckState(!startRequested); GrpcPreconditions.CheckState(!startRequested);
foreach (var entry in serviceDefinition.CallHandlers) foreach (var entry in serviceDefinition.GetCallHandlers())
{ {
callHandlers.Add(entry.Key, entry.Value); callHandlers.Add(entry.Key, entry.Value);
} }

Loading…
Cancel
Save