File: parent\Shared\Server\InterceptorPipelineBuilder.cs
Web Access
Project: ..\..\..\src\aspnetcore\src\Grpc\JsonTranscoding\src\Microsoft.AspNetCore.Grpc.JsonTranscoding\Microsoft.AspNetCore.Grpc.JsonTranscoding.csproj (Microsoft.AspNetCore.Grpc.JsonTranscoding)
#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 Grpc.AspNetCore.Server;
using Grpc.Core;
using Grpc.Core.Interceptors;
 
namespace Grpc.Shared.Server;
 
internal sealed class InterceptorPipelineBuilder<TRequest, TResponse>
    where TRequest : class
    where TResponse : class
{
    private readonly IReadOnlyList<InterceptorRegistration> _interceptors;
    private readonly InterceptorActivators _interceptorActivators;
 
    public InterceptorPipelineBuilder(IReadOnlyList<InterceptorRegistration> interceptors, InterceptorActivators interceptorActivators)
    {
        _interceptors = interceptors;
        _interceptorActivators = interceptorActivators;
    }
 
    public ClientStreamingServerMethod<TRequest, TResponse> ClientStreamingPipeline(ClientStreamingServerMethod<TRequest, TResponse> innerInvoker)
    {
        return BuildPipeline(innerInvoker, BuildInvoker);
 
        static ClientStreamingServerMethod<TRequest, TResponse> BuildInvoker(InterceptorRegistration interceptorRegistration, InterceptorActivators interceptorActivators, ClientStreamingServerMethod<TRequest, TResponse> next)
        {
            return async (requestStream, context) =>
            {
                var serviceProvider = context.GetHttpContext().RequestServices;
                var interceptorActivator = interceptorActivators.GetInterceptorActivator(interceptorRegistration.Type);
                var interceptorHandle = CreateInterceptor(interceptorRegistration, interceptorActivator, serviceProvider);
 
                try
                {
                    return await interceptorHandle.Instance.ClientStreamingServerHandler(requestStream, context, next);
                }
                finally
                {
                    await interceptorActivator.ReleaseAsync(interceptorHandle);
                }
            };
        }
    }
 
    internal DuplexStreamingServerMethod<TRequest, TResponse> DuplexStreamingPipeline(DuplexStreamingServerMethod<TRequest, TResponse> innerInvoker)
    {
        return BuildPipeline(innerInvoker, BuildInvoker);
 
        static DuplexStreamingServerMethod<TRequest, TResponse> BuildInvoker(InterceptorRegistration interceptorRegistration, InterceptorActivators interceptorActivators, DuplexStreamingServerMethod<TRequest, TResponse> next)
        {
            return async (requestStream, responseStream, context) =>
            {
                var serviceProvider = context.GetHttpContext().RequestServices;
                var interceptorActivator = interceptorActivators.GetInterceptorActivator(interceptorRegistration.Type);
                var interceptorHandle = CreateInterceptor(interceptorRegistration, interceptorActivator, serviceProvider);
 
                try
                {
                    await interceptorHandle.Instance.DuplexStreamingServerHandler(requestStream, responseStream, context, next);
                }
                finally
                {
                    await interceptorActivator.ReleaseAsync(interceptorHandle);
                }
            };
        }
    }
 
    internal ServerStreamingServerMethod<TRequest, TResponse> ServerStreamingPipeline(ServerStreamingServerMethod<TRequest, TResponse> innerInvoker)
    {
        return BuildPipeline(innerInvoker, BuildInvoker);
 
        static ServerStreamingServerMethod<TRequest, TResponse> BuildInvoker(InterceptorRegistration interceptorRegistration, InterceptorActivators interceptorActivators, ServerStreamingServerMethod<TRequest, TResponse> next)
        {
            return async (request, responseStream, context) =>
            {
                var serviceProvider = context.GetHttpContext().RequestServices;
                var interceptorActivator = interceptorActivators.GetInterceptorActivator(interceptorRegistration.Type);
                var interceptorHandle = CreateInterceptor(interceptorRegistration, interceptorActivator, serviceProvider);
 
                if (interceptorHandle.Instance == null)
                {
                    throw new InvalidOperationException($"Could not construct Interceptor instance for type {interceptorRegistration.Type.FullName}");
                }
 
                try
                {
                    await interceptorHandle.Instance.ServerStreamingServerHandler(request, responseStream, context, next);
                }
                finally
                {
                    await interceptorActivator.ReleaseAsync(interceptorHandle);
                }
            };
        }
    }
 
    internal UnaryServerMethod<TRequest, TResponse> UnaryPipeline(UnaryServerMethod<TRequest, TResponse> innerInvoker)
    {
        return BuildPipeline(innerInvoker, BuildInvoker);
 
        static UnaryServerMethod<TRequest, TResponse> BuildInvoker(InterceptorRegistration interceptorRegistration, InterceptorActivators interceptorActivators, UnaryServerMethod<TRequest, TResponse> next)
        {
            return async (request, context) =>
            {
                var serviceProvider = context.GetHttpContext().RequestServices;
                var interceptorActivator = interceptorActivators.GetInterceptorActivator(interceptorRegistration.Type);
                var interceptorHandle = CreateInterceptor(interceptorRegistration, interceptorActivator, serviceProvider);
 
                try
                {
                    return await interceptorHandle.Instance.UnaryServerHandler(request, context, next);
                }
                finally
                {
                    await interceptorActivator.ReleaseAsync(interceptorHandle);
                }
            };
        }
    }
 
    private T BuildPipeline<T>(T innerInvoker, Func<InterceptorRegistration, InterceptorActivators, T, T> wrapInvoker)
    {
        // The inner invoker will create the service instance and invoke the method
        var resolvedInvoker = innerInvoker;
 
        // The list is reversed during construction so the first interceptor is built last and invoked first
        for (var i = _interceptors.Count - 1; i >= 0; i--)
        {
            resolvedInvoker = wrapInvoker(_interceptors[i], _interceptorActivators, resolvedInvoker);
        }
 
        return resolvedInvoker;
    }
 
    private static GrpcActivatorHandle<Interceptor> CreateInterceptor(InterceptorRegistration interceptorRegistration, IGrpcInterceptorActivator interceptorActivator, IServiceProvider serviceProvider)
    {
        var interceptorHandle = interceptorActivator.Create(serviceProvider, interceptorRegistration);
 
        if (interceptorHandle.Instance == null)
        {
            throw new InvalidOperationException($"Could not construct Interceptor instance for type {interceptorRegistration.Type.FullName}");
        }
 
        return interceptorHandle;
    }
}