| File: StaticRouteHandlerModel\EndpointResponse.cs | Web Access |
| Project: src\aspnetcore\src\Http\Http.Extensions\gen\Microsoft.AspNetCore.Http.RequestDelegateGenerator\Microsoft.AspNetCore.Http.RequestDelegateGenerator.csproj (Microsoft.AspNetCore.Http.RequestDelegateGenerator) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.AspNetCore.Analyzers.RouteEmbeddedLanguage.Infrastructure; using Microsoft.AspNetCore.App.Analyzers.Infrastructure; using Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel.Emitters; using Microsoft.CodeAnalysis; namespace Microsoft.AspNetCore.Http.RequestDelegateGenerator.StaticRouteHandlerModel; using WellKnownType = WellKnownTypeData.WellKnownType; internal class EndpointResponse { public ITypeSymbol? ResponseType { get; set; } public ITypeSymbol WrappedResponseType { get; set; } public string WrappedResponseTypeDisplayName { get; set; } public string? ContentType { get; set; } public bool IsAwaitable { get; set; } public bool HasNoResponse { get; set; } public bool IsIResult { get; set; } public bool IsSerializable { get; set; } public bool IsEndpointMetadataProvider { get; set; } private WellKnownTypes WellKnownTypes { get; init; } internal EndpointResponse(IMethodSymbol method, WellKnownTypes wellKnownTypes) { WellKnownTypes = wellKnownTypes; ResponseType = UnwrapResponseType(method, out bool isAwaitable, out bool awaitableIsVoid); WrappedResponseType = method.ReturnType; WrappedResponseTypeDisplayName = method.ReturnType.ToDisplayString(EmitterConstants.DisplayFormat); IsAwaitable = isAwaitable; HasNoResponse = method.ReturnsVoid || awaitableIsVoid; IsIResult = GetIsIResult(); IsSerializable = GetIsSerializable(); ContentType = GetContentType(); IsEndpointMetadataProvider = ImplementsIEndpointMetadataProvider(ResponseType, wellKnownTypes); } private static bool ImplementsIEndpointMetadataProvider(ITypeSymbol? responseType, WellKnownTypes wellKnownTypes) => responseType == null ? false : responseType.Implements(wellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_Metadata_IEndpointMetadataProvider)); private ITypeSymbol? UnwrapResponseType(IMethodSymbol method, out bool isAwaitable, out bool awaitableIsVoid) { isAwaitable = false; awaitableIsVoid = false; var returnType = method.ReturnType; var task = WellKnownTypes.Get(WellKnownType.System_Threading_Tasks_Task); var taskOfT = WellKnownTypes.Get(WellKnownType.System_Threading_Tasks_Task_T); var valueTask = WellKnownTypes.Get(WellKnownType.System_Threading_Tasks_ValueTask); var valueTaskOfT = WellKnownTypes.Get(WellKnownType.System_Threading_Tasks_ValueTask_T); if (returnType.OriginalDefinition.Equals(taskOfT, SymbolEqualityComparer.Default) || returnType.OriginalDefinition.Equals(valueTaskOfT, SymbolEqualityComparer.Default)) { isAwaitable = true; awaitableIsVoid = false; return ((INamedTypeSymbol)returnType).TypeArguments[0]; } if (returnType.OriginalDefinition.Equals(task, SymbolEqualityComparer.Default) || returnType.OriginalDefinition.Equals(valueTask, SymbolEqualityComparer.Default)) { isAwaitable = true; awaitableIsVoid = true; return null; } return returnType; } private bool GetIsSerializable() => !IsIResult && !HasNoResponse && ResponseType != null && ResponseType.TypeKind != TypeKind.Error && ResponseType.SpecialType != SpecialType.System_String && ResponseType.SpecialType != SpecialType.System_Object; private bool GetIsIResult() { var resultType = WellKnownTypes.Get(WellKnownType.Microsoft_AspNetCore_Http_IResult); return WellKnownTypes.Implements(ResponseType, resultType) || SymbolEqualityComparer.Default.Equals(ResponseType, resultType); } private string? GetContentType() { // `void` returning methods do not have a Content-Type. // We don't have a strategy for resolving a Content-Type // from an IResult. Typically, this would be done via an // IEndpointMetadataProvider so we don't need to set a // Content-Type here. if (IsIResult || HasNoResponse) { return null; } return ResponseType!.SpecialType is SpecialType.System_String ? "text/plain; charset=utf-8" : "application/json"; } public override bool Equals(object obj) { return obj is EndpointResponse otherEndpointResponse && SymbolEqualityComparer.Default.Equals(otherEndpointResponse.ResponseType, ResponseType) && SymbolEqualityComparer.Default.Equals(otherEndpointResponse.WrappedResponseType, WrappedResponseType) && otherEndpointResponse.WrappedResponseTypeDisplayName.Equals(WrappedResponseTypeDisplayName, StringComparison.Ordinal) && otherEndpointResponse.IsAwaitable == IsAwaitable && otherEndpointResponse.HasNoResponse == HasNoResponse && otherEndpointResponse.IsIResult == IsIResult && string.Equals(otherEndpointResponse.ContentType, ContentType, StringComparison.OrdinalIgnoreCase); } public override int GetHashCode() => HashCode.Combine(SymbolEqualityComparer.Default.GetHashCode(ResponseType), SymbolEqualityComparer.Default.GetHashCode(WrappedResponseType), WrappedResponseTypeDisplayName, IsAwaitable, HasNoResponse, IsIResult, ContentType); }