1 #region Copyright notice and license 2 3 // Copyright 2018 gRPC authors. 4 // 5 // Licensed under the Apache License, Version 2.0 (the "License"); 6 // you may not use this file except in compliance with the License. 7 // You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, software 12 // distributed under the License is distributed on an "AS IS" BASIS, 13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 // See the License for the specific language governing permissions and 15 // limitations under the License. 16 17 #endregion 18 19 using System; 20 using System.Linq; 21 using Grpc.Core.Utils; 22 23 namespace Grpc.Core.Interceptors 24 { 25 /// <summary> 26 /// Extends the ServerServiceDefinition class to add methods used to register interceptors on the server side. 27 /// </summary> 28 public static class ServerServiceDefinitionExtensions 29 { 30 /// <summary> 31 /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that 32 /// intercepts incoming calls to the underlying service handler through the given interceptor. 33 /// </summary> 34 /// <param name="serverServiceDefinition">The <see cref="Grpc.Core.ServerServiceDefinition" /> instance to register interceptors on.</param> 35 /// <param name="interceptor">The interceptor to intercept the incoming invocations with.</param> 36 /// <remarks> 37 /// Multiple interceptors can be added on top of each other by calling 38 /// "serverServiceDefinition.Intercept(a, b, c)". The order of invocation will be "a", "b", and then "c". 39 /// Interceptors can be later added to an existing intercepted service definition, effectively 40 /// building a chain like "serverServiceDefinition.Intercept(c).Intercept(b).Intercept(a)". Note that 41 /// in this case, the last interceptor added will be the first to take control. 42 /// </remarks> Intercept(this ServerServiceDefinition serverServiceDefinition, Interceptor interceptor)43 public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, Interceptor interceptor) 44 { 45 GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition)); 46 GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor)); 47 48 var binder = new InterceptingServiceBinder(interceptor); 49 serverServiceDefinition.BindService(binder); 50 return binder.GetInterceptedServerServiceDefinition(); 51 } 52 53 /// <summary> 54 /// Returns a <see cref="Grpc.Core.ServerServiceDefinition" /> instance that 55 /// intercepts incoming calls to the underlying service handler through the given interceptors. 56 /// </summary> 57 /// <param name="serverServiceDefinition">The <see cref="Grpc.Core.ServerServiceDefinition" /> instance to register interceptors on.</param> 58 /// <param name="interceptors"> 59 /// An array of interceptors to intercept the incoming invocations with. 60 /// Control is passed to the interceptors in the order specified. 61 /// </param> 62 /// <remarks> 63 /// Multiple interceptors can be added on top of each other by calling 64 /// "serverServiceDefinition.Intercept(a, b, c)". The order of invocation will be "a", "b", and then "c". 65 /// Interceptors can be later added to an existing intercepted service definition, effectively 66 /// building a chain like "serverServiceDefinition.Intercept(c).Intercept(b).Intercept(a)". Note that 67 /// in this case, the last interceptor added will be the first to take control. 68 /// </remarks> Intercept(this ServerServiceDefinition serverServiceDefinition, params Interceptor[] interceptors)69 public static ServerServiceDefinition Intercept(this ServerServiceDefinition serverServiceDefinition, params Interceptor[] interceptors) 70 { 71 GrpcPreconditions.CheckNotNull(serverServiceDefinition, nameof(serverServiceDefinition)); 72 GrpcPreconditions.CheckNotNull(interceptors, nameof(interceptors)); 73 74 foreach (var interceptor in interceptors.Reverse()) 75 { 76 serverServiceDefinition = Intercept(serverServiceDefinition, interceptor); 77 } 78 79 return serverServiceDefinition; 80 } 81 82 /// <summary> 83 /// Helper for creating <c>ServerServiceDefinition</c> with intercepted handlers. 84 /// </summary> 85 private class InterceptingServiceBinder : ServiceBinderBase 86 { 87 readonly ServerServiceDefinition.Builder builder = ServerServiceDefinition.CreateBuilder(); 88 readonly Interceptor interceptor; 89 InterceptingServiceBinder(Interceptor interceptor)90 public InterceptingServiceBinder(Interceptor interceptor) 91 { 92 this.interceptor = GrpcPreconditions.CheckNotNull(interceptor, nameof(interceptor)); 93 } 94 GetInterceptedServerServiceDefinition()95 internal ServerServiceDefinition GetInterceptedServerServiceDefinition() 96 { 97 return builder.Build(); 98 } 99 AddMethod( Method<TRequest, TResponse> method, UnaryServerMethod<TRequest, TResponse> handler)100 public override void AddMethod<TRequest, TResponse>( 101 Method<TRequest, TResponse> method, 102 UnaryServerMethod<TRequest, TResponse> handler) 103 { 104 builder.AddMethod(method, (request, context) => interceptor.UnaryServerHandler(request, context, handler)); 105 } 106 AddMethod( Method<TRequest, TResponse> method, ClientStreamingServerMethod<TRequest, TResponse> handler)107 public override void AddMethod<TRequest, TResponse>( 108 Method<TRequest, TResponse> method, 109 ClientStreamingServerMethod<TRequest, TResponse> handler) 110 { 111 builder.AddMethod(method, (requestStream, context) => interceptor.ClientStreamingServerHandler(requestStream, context, handler)); 112 } 113 AddMethod( Method<TRequest, TResponse> method, ServerStreamingServerMethod<TRequest, TResponse> handler)114 public override void AddMethod<TRequest, TResponse>( 115 Method<TRequest, TResponse> method, 116 ServerStreamingServerMethod<TRequest, TResponse> handler) 117 { 118 builder.AddMethod(method, (request, responseStream, context) => interceptor.ServerStreamingServerHandler(request, responseStream, context, handler)); 119 } 120 AddMethod( Method<TRequest, TResponse> method, DuplexStreamingServerMethod<TRequest, TResponse> handler)121 public override void AddMethod<TRequest, TResponse>( 122 Method<TRequest, TResponse> method, 123 DuplexStreamingServerMethod<TRequest, TResponse> handler) 124 { 125 builder.AddMethod(method, (requestStream, responseStream, context) => interceptor.DuplexStreamingServerHandler(requestStream, responseStream, context, handler)); 126 } 127 } 128 } 129 } 130