| File: Internal\GrpcDataContractResolver.cs | Web Access |
| Project: src\aspnetcore\src\Grpc\JsonTranscoding\src\Microsoft.AspNetCore.Grpc.Swagger\Microsoft.AspNetCore.Grpc.Swagger.csproj (Microsoft.AspNetCore.Grpc.Swagger) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics.CodeAnalysis; using System.Linq; using Google.Protobuf.Reflection; using Google.Protobuf.WellKnownTypes; using Grpc.Shared; using Swashbuckle.AspNetCore.SwaggerGen; using Type = System.Type; namespace Microsoft.AspNetCore.Grpc.Swagger.Internal; internal sealed class GrpcDataContractResolver : ISerializerDataContractResolver { private readonly ISerializerDataContractResolver _innerContractResolver; private readonly DescriptorRegistry _descriptorRegistry; public GrpcDataContractResolver(ISerializerDataContractResolver innerContractResolver, DescriptorRegistry descriptorRegistry) { _innerContractResolver = innerContractResolver; _descriptorRegistry = descriptorRegistry; } public DataContract GetDataContractForType(Type type) { var descriptor = _descriptorRegistry.FindDescriptorByType(type); if (descriptor != null) { if (descriptor is MessageDescriptor messageDescriptor) { return ConvertMessage(messageDescriptor); } else if (descriptor is EnumDescriptor enumDescriptor) { return DataContract.ForPrimitive(type, DataType.String, dataFormat: null, value => { var match = enumDescriptor.Values.SingleOrDefault(v => v.Number == (int)value); var name = match?.Name ?? value.ToString(); return @"""" + name + @""""; }); } } return _innerContractResolver.GetDataContractForType(type); } private bool TryCustomizeMessage(MessageDescriptor messageDescriptor, [NotNullWhen(true)] out DataContract? dataContract) { // The messages serialized here should be kept in sync with ServiceDescriptionHelper.IsCustomType. if (ServiceDescriptorHelpers.IsWellKnownType(messageDescriptor)) { if (ServiceDescriptorHelpers.IsWrapperType(messageDescriptor)) { var field = messageDescriptor.Fields[Int32Value.ValueFieldNumber]; dataContract = _innerContractResolver.GetDataContractForType(MessageDescriptorHelpers.ResolveFieldType(field)); return true; } if (messageDescriptor.FullName == Timestamp.Descriptor.FullName || messageDescriptor.FullName == Duration.Descriptor.FullName || messageDescriptor.FullName == FieldMask.Descriptor.FullName) { dataContract = DataContract.ForPrimitive(messageDescriptor.ClrType, DataType.String, dataFormat: null); return true; } if (messageDescriptor.FullName == Struct.Descriptor.FullName) { dataContract = DataContract.ForObject(messageDescriptor.ClrType, Array.Empty<DataProperty>(), extensionDataType: typeof(Value)); return true; } if (messageDescriptor.FullName == ListValue.Descriptor.FullName) { dataContract = DataContract.ForArray(messageDescriptor.ClrType, typeof(Value)); return true; } if (messageDescriptor.FullName == Value.Descriptor.FullName) { dataContract = DataContract.ForPrimitive(messageDescriptor.ClrType, DataType.Unknown, dataFormat: null); return true; } if (messageDescriptor.FullName == Any.Descriptor.FullName) { var anyProperties = new List<DataProperty> { new DataProperty("@type", typeof(string), isRequired: true) }; dataContract = DataContract.ForObject(messageDescriptor.ClrType, anyProperties, extensionDataType: typeof(Value)); return true; } } dataContract = null; return false; } private DataContract ConvertMessage(MessageDescriptor messageDescriptor) { if (TryCustomizeMessage(messageDescriptor, out var dataContract)) { return dataContract; } var properties = new List<DataProperty>(); foreach (var field in messageDescriptor.Fields.InFieldNumberOrder()) { var fieldType = MessageDescriptorHelpers.ResolveFieldType(field); var propertyName = ServiceDescriptorHelpers.FormatUnderscoreName(field.Name, pascalCase: true, preservePeriod: false); var propertyInfo = messageDescriptor.ClrType.GetProperty(propertyName); properties.Add(new DataProperty(field.JsonName, fieldType, memberInfo: propertyInfo)); } var schema = DataContract.ForObject(messageDescriptor.ClrType, properties: properties); return schema; } }