private static AspNetCoreHttpEndpoint ReadMethodAsHttpEndpoint(AspNetCoreHttpController parent, MethodDeclarationSyntax syntax)
        {
            var attributes = syntax.DescendantNodes().OfType <AttributeListSyntax>().SelectMany(x => x.Attributes).ToList();

            var endpoint = new AspNetCoreHttpEndpoint(parent);

            endpoint.Name          = syntax.Identifier.ValueText.Trim();
            endpoint.FormattedName = syntax.Identifier.ValueText.CleanMethodName();


            endpoint.Virtual  = syntax.Modifiers.Any(x => x.Text == "virtual");
            endpoint.Override = syntax.Modifiers.Any(x => x.Text == "override");
            endpoint.New      = syntax.Modifiers.Any(x => x.Text == "new");


            //Ignore generator attribute
            endpoint.Ignored = attributes.HasAttribute <NotGeneratedAttribute>();


            //Route Attribute

            var routeAttribute = attributes.GetAttribute <RouteAttribute>();

            if (routeAttribute != null)            //Fetch route from RouteAttribute
            {
                endpoint.Route = new HttpRoute(routeAttribute.GetAttributeValue());
            }


            //HTTP Attribute
            var knownHttpAttributes = new List <string>
            {
                $"{Constants.Http}{HttpAttributeType.Delete}",
                $"{Constants.Http}{HttpAttributeType.Get}",
                $"{Constants.Http}{HttpAttributeType.Patch}",
                $"{Constants.Http}{HttpAttributeType.Post}",
                $"{Constants.Http}{HttpAttributeType.Put}",
            };

            var httpAttribute = attributes.SingleOrDefault(x => knownHttpAttributes.Any(y => x.Name.ToFullString().MatchesAttribute(y)));

            if (httpAttribute == null)
            {
                endpoint.Ignored = true;
            }
            else
            {
                var httpType = (HttpAttributeType)Enum.Parse(typeof(HttpAttributeType),
                                                             httpAttribute.Name
                                                             .ToFullString()
                                                             .Replace(Constants.Http, "")
                                                             .Replace(Constants.Attribute, ""));

                endpoint.HttpType = Helpers.HttpMethodFromEnum(httpType);
            }



            if (endpoint.Route == null && httpAttribute?.ArgumentList != null)            //If Route was never fetched from RouteAttribute or if they used the Http(template) override
            {
                endpoint.Route = new HttpRoute(httpAttribute.GetAttributeValue());
            }

            //Ignore method if it doesn't have a route or http attribute
            if (endpoint.Route == null && httpAttribute == null)
            {
                endpoint.Ignored = true;
                return(endpoint);
            }

            if (endpoint.Route == null)
            {
                endpoint.Route = new HttpRoute(string.Empty);
            }

            var versionAttribute = attributes.GetAttribute <ApiVersionAttribute>();

            if (versionAttribute != null)
            {
                var version = new ApiVersionDefinition(versionAttribute);

                var versionConstraint = endpoint.Route.Constraints.OfType <ApiVersionContraint>().SingleOrDefault();
                if (versionConstraint != null)
                {
                    endpoint.Route.Version = new Framework.AspNetCoreHttp.Routes.ApiVersion(version.Version, false);
                }
                else
                {
                    endpoint.Route.Version = new Framework.AspNetCoreHttp.Routes.ApiVersion(version.Version, true);
                }
            }


            if (endpoint.Route.Version != null && parent.Route.Version != null)
            {
                throw new NotSupportedException($"Endpoint {parent.Name}.{endpoint.FormattedName} has {nameof(ApiVersionAttribute)} on both it's method and class");
            }

            //Obsolete Attribute
            var obsoleteAttribute = attributes.GetAttribute <ObsoleteAttribute>();

            if (obsoleteAttribute != null)
            {
                endpoint.Obsolete        = true;
                endpoint.ObsoleteMessage = obsoleteAttribute.GetAttributeValue();
            }

            //Authorize Attribute
            endpoint.IsSecured = attributes.HasAttribute <AuthorizeAttribute>();


            //Response types
            var responseTypes = attributes.GetAttributes <ProducesResponseTypeAttribute>();
            var responses     = responseTypes.Select(x => new ResponseTypeDefinition(x)).ToList();

            responses.Add(new ResponseTypeDefinition(true));

            endpoint.ResponseTypes = responses.Select(x => new ResponseType(x.Type, Helpers.EnumParse <HttpStatusCode>(x.StatusValue))).ToList();

            var duplicateResponseTypes = endpoint.GetResponseTypes().GroupBy(x => x.Status).Where(x => x.Count() > 1).ToList();

            if (duplicateResponseTypes.Any())
            {
                throw new NotSupportedException($"Endpoint has multiple response types of the same status defined. {string.Join(", ", duplicateResponseTypes.Select(x => x.Key?.ToString()))}");
            }
            //Add after so we don't get duplicate error from the null Status
            endpoint.ResponseTypes.Add(new ExceptionResponseType());



            var parameters = syntax.ParameterList.Parameters.Select(x => new ParameterDefinition(x, endpoint.GetFullRoute(parent))).ToList();


            var routeParams = parameters.Where(x => x.Options.FromRoute).Select(x => new RouteParameter(x.RouteName, x.Type, x.Default)).ToList();
            var queryParams = parameters.Where(x => x.Options.FromQuery).Select(x => new QueryParameter(x.Options.QueryName, x.Type, x.Default, x.Options.QueryObject)).ToList();
            var bodyParam   = parameters.Where(x => x.Options.FromBody).Select(x => new BodyParameter(x.Name, x.Type, x.Default)).SingleOrDefault();


            endpoint.Parameters = routeParams.Cast <IParameter>().Union(queryParams).Union(new List <IParameter> {
                bodyParam
            }).NotNull().ToList();

            endpoint.Parameters.Add(new CancellationTokenModifier());
            endpoint.Parameters.Add(new CookieModifier());
            endpoint.Parameters.Add(new HeadersModifier());
            endpoint.Parameters.Add(new TimeoutModifier());
            if (endpoint.IsSecured)
            {
                endpoint.Parameters.Add(new SecurityModifier());
            }


            var parameterHeaders = attributes.GetAttributes <HeaderParameterAttribute>()
                                   .Select(x => new ParameterHeaderDefinition(x))
                                   .ToList();

            endpoint.ParameterHeader = parameterHeaders.Select(x => new ParameterHeader(x.Name, x.Type, x.DefaultValue)).ToList();



            var headers = attributes.GetAttributes <IncludeHeaderAttribute>()
                          .Select(x => new HeaderDefinition(x))
                          .ToList();

            endpoint.ConstantHeader = headers.Select(x => new ConstantHeader(x.Name, x.Value)).ToList();


            var rawReturnType = syntax.ReturnType?.ToFullString();

            var returnType = Helpers.GetTypeFromString(rawReturnType.Trim());

            while (returnType.IsContainerReturnType())
            {
                returnType = returnType.Arguments.SingleOrDefault();
            }

            if (Helpers.IsType(typeof(IActionResult).FullName, returnType?.Name))
            {
                returnType = null;
            }

            if (returnType?.Name == "void" ||
                (Helpers.IsType(typeof(Task).FullName, returnType?.Name) && (!returnType?.Arguments.Any() ?? false)))
            {
                returnType = null;
            }

            if (returnType.IsFileReturnType())
            {
                returnType             = new Helpers.TypeString(typeof(Stream).FullName);
                endpoint.ReturnsStream = true;
            }

            rawReturnType = returnType?.ToString();

            endpoint.ReturnType = rawReturnType?.Trim();

            var okStatus = endpoint.ResponseTypes.SingleOrDefault(x => x.Status == HttpStatusCode.OK);

            if (okStatus != null &&
                endpoint.ReturnType != null &&
                Helpers.IsType(okStatus.ActionType, endpoint.ReturnType))
            {
                //Remove the OkStatus since it is the same as the method return
                endpoint.ResponseTypes.Remove(okStatus);
            }
            else if (okStatus != null &&
                     endpoint.ReturnType != null &&
                     !Helpers.IsType(okStatus.ActionType, endpoint.ReturnType))
            {
                throw new NotSupportedException($"Endpoint {parent.Name}.{endpoint.FormattedName} has a OK response type of {okStatus.ActionType}, but the method return {endpoint.ReturnType}");
            }

            var duplicateParameters = endpoint.GetParametersWithoutResponseTypes().GroupBy(x => x.Name).Where(x => x.Count() > 1).ToList();

            if (duplicateParameters.Any())
            {
                throw new NotSupportedException($"Endpoint {parent.Name}.{endpoint.FormattedName} has multiple parameters of the same name defined. {string.Join(", ", duplicateParameters.Select(x => x.Key?.ToString()))}");
            }

            var invalidParameters = endpoint.GetParameters().Where(x => !Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsValidIdentifier(x.Name)).ToList();

            if (invalidParameters.Any())
            {
                throw new NotSupportedException($"Endpoint {parent.Name}.{endpoint.FormattedName} has parameters that are invalid variable names. {string.Join(", ", invalidParameters.Select(x => x.Name))}");
            }

            var fullRoute = endpoint.GetFullRoute(parent);

            if (fullRoute?.Version?.Query ?? false)
            {
                endpoint.Parameters.Add(new QueryParameter($"api-version={fullRoute?.Version}"));
            }


            return(endpoint);
        }
        public static FunctionEndpoint ReadMethodAsFunction(MethodDeclarationSyntax syntax, HostJson hostData)
        {
            var attributes = syntax.DescendantNodes().OfType <AttributeListSyntax>().SelectMany(x => x.Attributes).ToList();

            var endpoint = new FunctionEndpoint();

            try
            {
                var endpointName = attributes.GetAttribute <FunctionNameAttribute>();

                if (endpointName == null)
                {
                    endpoint.Ignored = true;
                    return(endpoint);
                }

                endpoint.Name = endpointName.GetAttributeValue();

                //Ignore generator attribute
                endpoint.Ignored = attributes.HasAttribute <NotGeneratedAttribute>();


                //Obsolete Attribute
                var obsoleteAttribute = attributes.GetAttribute <ObsoleteAttribute>();
                if (obsoleteAttribute != null)
                {
                    endpoint.Obsolete        = true;
                    endpoint.ObsoleteMessage = obsoleteAttribute.GetAttributeValue();
                }

                //Response types
                var responseTypes = attributes.GetAttributes <ProducesResponseTypeAttribute>();
                var responses     = responseTypes.Select(x => new ResponseTypeDefinition(x)).ToList();
                responses.Add(new ResponseTypeDefinition(true));

                endpoint.ResponseTypes = responses.Select(x => new ResponseType(x.Type, Helpers.EnumParse <HttpStatusCode>(x.StatusValue))).ToList();

                var duplicateResponseTypes = endpoint.GetResponseTypes().GroupBy(x => x.Status).Where(x => x.Count() > 1).ToList();

                if (duplicateResponseTypes.Any())
                {
                    throw new NotSupportedException($"Endpoint has multiple response types of the same status defined. {string.Join(", ", duplicateResponseTypes.Select(x => x.Key?.ToString()))}");
                }
                //Add after so we don't get duplicate error from the null Status
                endpoint.ResponseTypes.Add(new ExceptionResponseType());


                //Need to check if the function has a HttpTrigger
                var httpTriggerAttribute = syntax.ParameterList.Parameters.SingleOrDefault(x => x.AttributeLists.SelectMany(y => y.Attributes).HasAttribute <HttpTriggerAttribute>());

                if (httpTriggerAttribute == null)
                {
                    endpoint.Ignored = true;
                    return(endpoint);
                }

                var triggerAttribute = new HttpTriggerParameter(httpTriggerAttribute);

                endpoint.SupportedMethods = triggerAttribute.Methods;

                var routePrefix = hostData?.http?.routePrefix ?? "api";

                if (triggerAttribute.Route != null)
                {
                    var route = triggerAttribute.Route.TrimStart('/');

                    if (!string.IsNullOrEmpty(routePrefix))
                    {
                        if (!route.StartsWith(routePrefix))
                        {
                            route = $"{routePrefix}/" + route;
                        }

                        route = "/" + route;
                    }

                    endpoint.Route = new HttpRoute(route);
                }
                else
                {
                    if (!string.IsNullOrEmpty(routePrefix))
                    {
                        endpoint.Route = new HttpRoute($"{routePrefix}/{endpoint.Name}");
                    }
                    else
                    {
                        endpoint.Route = new HttpRoute($"{endpoint.Name}");
                    }
                }


                var expectedBodyParameters = attributes.GetAttributes <ExpectedBodyParameterAttribute>()
                                             .Select(x => new ExpectedBodyParamterDefinition(x))
                                             .GroupBy(x => x.Method)
                                             .ToDictionary(x => x.Key, y => y.Select(z => (IParameter) new BodyParameter("body", z.Type, null)));

                var expectedQueryParameters = attributes.GetAttributes <ExpectedQueryParameterAttribute>()
                                              .Select(x => new ExpectedQueryParamterDefinition(x))
                                              .GroupBy(x => x.Method)
                                              .ToDictionary(x => x.Key, y => y.Select(z => (IParameter) new QueryParameter(z.Name, z.Type, null, z.IsQueryObject)));

                endpoint.HttpParameters = expectedBodyParameters.Union(expectedQueryParameters).ToDictionary();

                var parameters = syntax.ParameterList.Parameters.Select(x => new ParameterDefinition(x, endpoint.GetFullRoute())).ToList();

                var routeParams = parameters.Where(x => x.Options.FromRoute).Select(x => new RouteParameter(x.RouteName, x.Type, x.Default)).ToList();

                endpoint.Parameters = routeParams.Cast <IParameter>().NotNull().ToList();

                endpoint.Parameters.Add(new CancellationTokenModifier());
                endpoint.Parameters.Add(new CookieModifier());
                endpoint.Parameters.Add(new HeadersModifier());
                endpoint.Parameters.Add(new TimeoutModifier());

                if (triggerAttribute.AuthLevel == AuthorizationLevel.User)
                {
                    if (!endpoint.ResponseTypes.Any(x => x.Status == HttpStatusCode.Unauthorized))
                    {
                        endpoint.ResponseTypes.Add(new ResponseType(HttpStatusCode.Unauthorized));
                    }

                    endpoint.Parameters.Add(new SecurityModifier());
                }
                else if (triggerAttribute.AuthLevel == AuthorizationLevel.Anonymous)
                {
                }
                else
                {
                    if (!endpoint.ResponseTypes.Any(x => x.Status == HttpStatusCode.Unauthorized))
                    {
                        endpoint.ResponseTypes.Add(new ResponseType(HttpStatusCode.Unauthorized));
                    }

                    endpoint.Parameters.Add(new FunctionAuthModifier());
                }


                var parameterHeaders = attributes.GetAttributes <HeaderParameterAttribute>()
                                       .Select(x => new ParameterHeaderDefinition(x))
                                       .ToList();
                endpoint.ParameterHeader = parameterHeaders.Select(x => new ParameterHeader(x.Name, x.Type, x.DefaultValue)).ToList();



                var headers = attributes.GetAttributes <IncludeHeaderAttribute>()
                              .Select(x => new HeaderDefinition(x))
                              .ToList();
                endpoint.ConstantHeader = headers.Select(x => new ConstantHeader(x.Name, x.Value)).ToList();


                var rawReturnType = syntax.ReturnType?.ToFullString();

                var returnType = Helpers.GetTypeFromString(rawReturnType.Trim());

                while (returnType.IsContainerReturnType())
                {
                    returnType = returnType.Arguments.SingleOrDefault();
                }

                if (Helpers.IsType(typeof(IActionResult).FullName, returnType?.Name))
                {
                    returnType = null;
                }

                if (returnType?.Name == "void" ||
                    (Helpers.IsType(typeof(Task).FullName, returnType?.Name) && (!returnType?.Arguments.Any() ?? false)))
                {
                    returnType = null;
                }

                if (returnType.IsFileReturnType())
                {
                    returnType             = new Helpers.TypeString(typeof(Stream).FullName);
                    endpoint.ReturnsStream = true;
                }

                rawReturnType = returnType?.ToString();

                endpoint.ReturnType = rawReturnType?.Trim();

                foreach (var method in endpoint.SupportedMethods)
                {
                    var duplicateParameters = endpoint.GetParametersWithoutResponseTypesForHttpMethod(method).GroupBy(x => x.Name).Where(x => x.Count() > 1).ToList();

                    if (duplicateParameters.Any())
                    {
                        throw new NotSupportedException($"Function has multiple parameters of the same name defined. {string.Join(", ", duplicateParameters.Select(x => x.Key?.ToString()))}");
                    }


                    var invalidParameters = endpoint.GetParametersForHttpMethod(method).Where(x => !Microsoft.CodeAnalysis.CSharp.SyntaxFacts.IsValidIdentifier(x.Name)).ToList();

                    if (invalidParameters.Any())
                    {
                        throw new NotSupportedException($"Function {endpoint.Name} has parameters that are invalid variable names. {string.Join(", ", invalidParameters.Select(x => x.Name))}");
                    }
                }
            }
            catch (NotSupportedException nse)
            {
                if (endpoint.Ignored)
                {
                    return(endpoint);
                }

                endpoint.Failed = true;
                endpoint.Error  = nse.Message;
            }
#if !DEBUG
            catch (Exception ex)
            {
                endpoint.Failed            = true;
                endpoint.UnexpectedFailure = true;
                endpoint.Error             = ex.ToString();
            }
#endif


            return(endpoint);
        }
Exemple #3
0
        private static HttpEndpoint ReadMethodAsHttpEndpoint(HttpController parent, MethodDeclarationSyntax syntax)
        {
            var attributes = syntax.DescendantNodes().OfType <AttributeListSyntax>().SelectMany(x => x.Attributes).ToList();

            var endpoint = new HttpEndpoint(parent);

            endpoint.Name = syntax.Identifier.ValueText.CleanMethodName();


            endpoint.Virtual  = syntax.Modifiers.Any(x => x.Text == "virtual");
            endpoint.Override = syntax.Modifiers.Any(x => x.Text == "override");
            endpoint.New      = syntax.Modifiers.Any(x => x.Text == "new");


            //Ignore generator attribute
            endpoint.Ignored = attributes.SingleOrDefault(x => x.Name.ToFullString().MatchesAttribute(nameof(NotGeneratedAttribute))) != null;


            //Route Attribute

            var routeAttribute = attributes.SingleOrDefault(x => x.Name.ToFullString().MatchesAttribute(nameof(RouteAttribute)));

            if (routeAttribute != null)            //Fetch route from RouteAttribute
            {
                endpoint.Route = new HttpRoute(routeAttribute.ArgumentList.Arguments.ToFullString().Replace("\"", "").Trim());
            }


            //HTTP Attribute
            var knownHttpAttributes = new List <string>
            {
                $"{Constants.Http}{HttpAttributeType.Delete}",
                $"{Constants.Http}{HttpAttributeType.Get}",
                $"{Constants.Http}{HttpAttributeType.Patch}",
                $"{Constants.Http}{HttpAttributeType.Post}",
                $"{Constants.Http}{HttpAttributeType.Put}",
            };

            var httpAttribute = attributes.SingleOrDefault(x => knownHttpAttributes.Any(y => x.Name.ToFullString().MatchesAttribute(y)));

            if (httpAttribute == null)
            {
                endpoint.Ignored = true;
            }
            else
            {
                var httpType = (HttpAttributeType)Enum.Parse(typeof(HttpAttributeType),
                                                             httpAttribute.Name
                                                             .ToFullString()
                                                             .Replace(Constants.Http, "")
                                                             .Replace(Constants.Attribute, ""));

                endpoint.HttpType = Helpers.HttpMethodFromEnum(httpType);
            }



            if (endpoint.Route == null && httpAttribute?.ArgumentList != null)            //If Route was never fetched from RouteAttribute or if they used the Http(template) override
            {
                endpoint.Route = new HttpRoute(httpAttribute.ArgumentList.Arguments.ToFullString().Replace("\"", "").Trim());
            }

            //Ignore method if it doesn't have a route or http attribute
            if (endpoint.Route == null && httpAttribute == null)
            {
                endpoint.Ignored = true;
                return(endpoint);
            }


            //Obsolete Attribute
            var obsoleteAttribute = attributes.SingleOrDefault(x => x.Name.ToFullString().MatchesAttribute(nameof(ObsoleteAttribute)));

            if (obsoleteAttribute != null)
            {
                endpoint.Obsolete        = true;
                endpoint.ObsoleteMessage = obsoleteAttribute.ArgumentList.Arguments.ToFullString().Replace("\"", "").Trim();
            }

            //Authorize Attribute
            endpoint.IsSecured = attributes.SingleOrDefault(x => x.Name.ToFullString().MatchesAttribute(nameof(AuthorizeAttribute))) != null;


            //Response types
            var responseTypes = attributes.Where(x => x.Name.ToFullString().MatchesAttribute(nameof(ProducesResponseTypeAttribute)));
            var responses     = responseTypes.Select(x => new ResponseTypeDefinition(x)).ToList();

            responses.Add(new ResponseTypeDefinition(true));

            endpoint.ResponseTypes = responses.Select(x => new ResponseType(x.Type, Helpers.EnumParse <HttpStatusCode>(x.StatusValue))).ToList();

            var duplicateResponseTypes = endpoint.GetResponseTypes().GroupBy(x => x.Status).Where(x => x.Count() > 1).ToList();

            if (duplicateResponseTypes.Any())
            {
                throw new NotSupportedException($"Endpoint has multiple response types of the same status defined. {string.Join(", ", duplicateResponseTypes.Select(x => x.Key?.ToString()))}");
            }
            //Add after so we don't get duplicate error from the null Status
            endpoint.ResponseTypes.Add(new ExceptionResponseType());



            var parameters = syntax.ParameterList.Parameters.Select(x => new ParameterDefinition(x, endpoint.GetFullRoute(parent))).ToList();


            var routeParams = parameters.Where(x => x.Options.FromRoute).Select(x => new RouteParameter(x.RouteName, x.Type, x.Default)).ToList();
            var queryParams = parameters.Where(x => x.Options.FromQuery).Select(x => new QueryParameter(x.Options.QueryName, x.Type, x.Default, x.Options.QueryObject)).ToList();
            var bodyParams  = parameters.Where(x => x.Options.FromBody).Select(x => new BodyParameter(x.Name, x.Type, x.Default)).SingleOrDefault();


            endpoint.Parameters = routeParams.Cast <IParameter>().Union(queryParams).Union(new List <IParameter> {
                bodyParams
            }).NotNull().ToList();

            endpoint.Parameters.Add(new CancellationTokenModifier());
            endpoint.Parameters.Add(new CookieModifier());
            endpoint.Parameters.Add(new HeadersModifier());
            endpoint.Parameters.Add(new TimeoutModifier());
            if (endpoint.IsSecured)
            {
                endpoint.Parameters.Add(new SecurityModifier());
            }


            var parameterHeaders = attributes.Where(x => x.Name.ToFullString().MatchesAttribute(nameof(HeaderParameterAttribute)))
                                   .Select(x => new ParameterHeaderDefinition(x))
                                   .ToList();

            endpoint.ParameterHeader = parameterHeaders.Select(x => new ParameterHeader(x.Name, x.Type, x.DefaultValue)).ToList();



            var headers = attributes.Where(x => x.Name.ToFullString().MatchesAttribute(nameof(IncludeHeaderAttribute)))
                          .Select(x => new HeaderDefinition(x))
                          .ToList();

            endpoint.ConstantHeader = headers.Select(x => new ConstantHeader(x.Name, x.Value)).ToList();


            var rawReturnType = syntax.ReturnType?.ToFullString();

            HashSet <string> returnContainerTypes = new HashSet <string>()
            {
                typeof(ValueTask).FullName,
                typeof(Task).FullName,
                typeof(ActionResult).FullName
            };


            var returnType = Helpers.GetTypeFromString(rawReturnType.Trim());

            while (returnContainerTypes.Any(x => Helpers.IsType(x, returnType?.Name)))
            {
                returnType = returnType.Arguments.SingleOrDefault();
            }

            if (Helpers.IsType(typeof(IActionResult).FullName, returnType?.Name))
            {
                returnType = null;
            }

            if (returnType?.Name == "void" ||
                (Helpers.IsType(typeof(Task).FullName, returnType?.Name) && (!returnType?.Arguments.Any() ?? false)))
            {
                returnType = null;
            }

            HashSet <string> fileResults = new HashSet <string>()
            {
                nameof(PhysicalFileResult),
                nameof(FileResult),
                nameof(FileContentResult),
                nameof(FileStreamResult),
                nameof(VirtualFileResult)
            };

            if (fileResults.Any(x => Helpers.IsType(x, returnType?.Name)))
            {
                returnType             = new Helpers.TypeString(typeof(Stream).FullName);
                endpoint.ReturnsStream = true;
            }

            rawReturnType = returnType?.ToString();

            endpoint.ReturnType = rawReturnType;



            var duplicateParameters = endpoint.GetParametersWithoutResponseTypes().GroupBy(x => x.Name).Where(x => x.Count() > 1).ToList();

            if (duplicateParameters.Any())
            {
                throw new NotSupportedException($"Endpoint has multiple parameters of the same name defined. {string.Join(", ", duplicateParameters.Select(x => x.Key?.ToString()))}");
            }



            return(endpoint);
        }