| File: Internal\Binding\ReflectionServiceInvokerResolver.cs | Web Access |
| Project: src\aspnetcore\src\Grpc\JsonTranscoding\src\Microsoft.AspNetCore.Grpc.JsonTranscoding\Microsoft.AspNetCore.Grpc.JsonTranscoding.csproj (Microsoft.AspNetCore.Grpc.JsonTranscoding) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Reflection; using Google.Api; using Google.Protobuf.Reflection; using Microsoft.AspNetCore.Routing; namespace Microsoft.AspNetCore.Grpc.JsonTranscoding.Internal.Binding; internal sealed class ReflectionServiceInvokerResolver<TService> : IServiceInvokerResolver<TService> where TService : class { private readonly Type _declaringType; public ReflectionServiceInvokerResolver(Type declaringType) { _declaringType = declaringType; } public (TDelegate invoker, List<object> metadata) CreateModelCore<TDelegate>( string methodName, Type[] methodParameters, string verb, HttpRule httpRule, MethodDescriptor methodDescriptor) where TDelegate : Delegate { var handlerMethod = GetMethod(methodName, methodParameters); if (handlerMethod == null) { throw new InvalidOperationException($"Could not find '{methodName}' on {typeof(TService)}."); } var invoker = (TDelegate)Delegate.CreateDelegate(typeof(TDelegate), handlerMethod); var metadata = new List<object>(); // Add type metadata first so it has a lower priority metadata.AddRange(typeof(TService).GetCustomAttributes(inherit: true)); // Add method metadata last so it has a higher priority metadata.AddRange(handlerMethod.GetCustomAttributes(inherit: true)); metadata.Add(new HttpMethodMetadata(new[] { verb })); // Add protobuf service method descriptor. // Is used by swagger generation to identify gRPC JSON transcoding APIs. metadata.Add(new GrpcJsonTranscodingMetadata(methodDescriptor, httpRule)); return (invoker, metadata); } private MethodInfo? GetMethod(string methodName, Type[] methodParameters) { Type? currentType = typeof(TService); while (currentType != null) { var matchingMethod = currentType.GetMethod( methodName, BindingFlags.Public | BindingFlags.Instance, binder: null, types: methodParameters, modifiers: null); if (matchingMethod == null) { return null; } // Validate that the method overrides the virtual method on the base service type. // If there is a method with the same name it will hide the base method. Ignore it, // and continue searching on the base type. if (matchingMethod.IsVirtual) { var baseDefinitionMethod = matchingMethod.GetBaseDefinition(); if (baseDefinitionMethod != null && baseDefinitionMethod.DeclaringType == _declaringType) { return matchingMethod; } } currentType = currentType.BaseType; } return null; } }