Esempio n. 1
0
        private AspNetCoreOperationProcessorContext GetContext(ApiDescription apiDescription)
        {
            var operationDescription = new OpenApiOperationDescription {
                Operation = new OpenApiOperation()
            };
            var swaggerSettings         = new AspNetCoreOpenApiDocumentGeneratorSettings();
            var document                = new OpenApiDocument();
            var schemaGeneratorSettings = new OpenApiDocumentGeneratorSettings();
            var schemaGenerator         = new OpenApiSchemaGenerator(schemaGeneratorSettings);
            var schemaResolver          = new OpenApiSchemaResolver(document, schemaGeneratorSettings);

            swaggerSettings.SchemaGenerator = schemaGenerator;

            var context = new AspNetCoreOperationProcessorContext(
                document,
                operationDescription,
                GetType(),
                GetType().GetMethod(nameof(SomeAction), BindingFlags.NonPublic | BindingFlags.Instance),
                new OpenApiDocumentGenerator(swaggerSettings, schemaResolver),
                schemaGenerator,
                schemaResolver,
                swaggerSettings,
                new List <OpenApiOperationDescription>())
            {
                ApiDescription = apiDescription,
            };

            return(context);
        }
Esempio n. 2
0
        private void ProcessSwaggerTagsAttribute(OpenApiDocument document, OpenApiOperationDescription operationDescription, MethodInfo methodInfo)
        {
            dynamic tagsAttribute = methodInfo
                                    .GetCustomAttributes()
                                    .FirstAssignableToTypeNameOrDefault("SwaggerTagsAttribute", TypeNameStyle.Name);

            if (tagsAttribute != null)
            {
                var tags = ((string[])tagsAttribute.Tags).ToList();
                foreach (var tag in tags)
                {
                    if (operationDescription.Operation.Tags.All(t => t != tag))
                    {
                        operationDescription.Operation.Tags.Add(tag);
                    }

                    if (ObjectExtensions.HasProperty(tagsAttribute, "AddToDocument") && tagsAttribute.AddToDocument)
                    {
                        if (document.Tags == null)
                        {
                            document.Tags = new List <OpenApiTag>();
                        }

                        if (document.Tags.All(t => t.Name != tag))
                        {
                            document.Tags.Add(new OpenApiTag {
                                Name = tag
                            });
                        }
                    }
                }
            }
        }
        private async Task <bool> GenerateForAzureFunctionClassAsync(OpenApiDocument document, Type staticAzureFunctionClassType,
                                                                     OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver, IList <string> functionNames)
        {
            var operations = new List <Tuple <OpenApiOperationDescription, MethodInfo> >();

            foreach (var method in GetActionMethods(staticAzureFunctionClassType, functionNames))
            {
                var httpPaths   = GetHttpPaths(method);
                var httpMethods = GetSupportedHttpMethods(method);

                foreach (var httpPath in httpPaths)
                {
                    foreach (var httpMethod in httpMethods)
                    {
                        var operationDescription = new OpenApiOperationDescription
                        {
                            Path      = httpPath,
                            Method    = httpMethod,
                            Operation = new OpenApiOperation
                            {
                                IsDeprecated = method.GetCustomAttribute <ObsoleteAttribute>() != null,
                                OperationId  = GetOperationId(document, staticAzureFunctionClassType.Name, method)
                            }
                        };

                        operations.Add(new Tuple <OpenApiOperationDescription, MethodInfo>(operationDescription, method));
                    }
                }
            }

            return(await AddOperationDescriptionsToDocumentAsync(document, staticAzureFunctionClassType, operations,
                                                                 swaggerGenerator, schemaResolver));
        }
 private void EnsureSingleBodyParameter(OpenApiOperationDescription operationDescription)
 {
     if (operationDescription.Operation.ActualParameters.Count(p => p.Kind == OpenApiParameterKind.Body) > 1)
     {
         throw new InvalidOperationException("The operation '" + operationDescription.Operation.OperationId + "' has more than one body parameter.");
     }
 }
        private void ApplyOpenApiBodyParameterAttribute(OpenApiOperationDescription operationDescription, MethodInfo methodInfo)
        {
            dynamic bodyParameterAttribute = methodInfo.GetCustomAttributes()
                                             .FirstAssignableToTypeNameOrDefault("OpenApiBodyParameterAttribute", TypeNameStyle.Name);

            if (bodyParameterAttribute != null)
            {
                if (operationDescription.Operation.RequestBody == null)
                {
                    operationDescription.Operation.RequestBody = new OpenApiRequestBody();
                }

                var mimeTypes = ObjectExtensions.HasProperty(bodyParameterAttribute, "MimeType") ?
                                new string[] { bodyParameterAttribute.MimeType } : bodyParameterAttribute.MimeTypes;

                foreach (var mimeType in mimeTypes)
                {
                    operationDescription.Operation.RequestBody.Content[mimeType] = new OpenApiMediaType
                    {
                        Schema = mimeType == "application/json" ? JsonSchema.CreateAnySchema() : new JsonSchema
                        {
                            Type   = _settings.SchemaType == SchemaType.Swagger2 ? JsonObjectType.File : JsonObjectType.String,
                            Format = _settings.SchemaType == SchemaType.Swagger2 ? null : JsonFormatStrings.Binary,
                        }
                    };
                }
            }
        }
 private void UpdateConsumedTypes(OpenApiOperationDescription operationDescription)
 {
     if (operationDescription.Operation.ActualParameters.Any(p => p.IsBinary || p.ActualSchema.IsBinary))
     {
         operationDescription.Operation.TryAddConsumes("multipart/form-data");
     }
 }
Esempio n. 7
0
        public void ProcessAsync_Adds200StatusCodeForVoidResponse()
        {
            // Arrange
            var apiDescription = new ApiDescription
            {
                SupportedResponseTypes =
                {
                    new ApiResponseType
                    {
                        Type       = typeof(void),
                        StatusCode = 0,
                    }
                }
            };

            var operationDescription = new OpenApiOperationDescription {
                Operation = new OpenApiOperation()
            };
            var context   = GetContext(apiDescription);
            var processor = new OperationResponseProcessor((AspNetCoreOpenApiDocumentGeneratorSettings)context.Settings);

            // Act
            processor.Process(context);

            // Assert
            Assert.Collection(
                context.OperationDescription.Operation.Responses,
                kvp =>
            {
                Assert.Equal("200", kvp.Key);
                Assert.Null(kvp.Value.Schema);
            });
        }
Esempio n. 8
0
        /// <exception cref="InvalidOperationException">The operation has more than one body parameter.</exception>
        private bool GenerateForController(OpenApiDocument document, Type controllerType, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver)
        {
            var hasIgnoreAttribute = controllerType.GetTypeInfo()
                                     .GetCustomAttributes()
                                     .GetAssignableToTypeName("SwaggerIgnoreAttribute", TypeNameStyle.Name)
                                     .Any();

            if (hasIgnoreAttribute)
            {
                return(false);
            }

            var operations = new List <Tuple <OpenApiOperationDescription, MethodInfo> >();

            var currentControllerType = controllerType;

            while (currentControllerType != null)
            {
                foreach (var method in GetActionMethods(currentControllerType))
                {
                    var httpPaths   = GetHttpPaths(controllerType, method).ToList();
                    var httpMethods = GetSupportedHttpMethods(method).ToList();

                    foreach (var httpPath in httpPaths)
                    {
                        foreach (var httpMethod in httpMethods)
                        {
                            var isPathAlreadyDefinedInInheritanceHierarchy =
                                operations.Any(o => o.Item1.Path == httpPath &&
                                               o.Item1.Method == httpMethod &&
                                               o.Item2.DeclaringType != currentControllerType &&
                                               o.Item2.DeclaringType.IsAssignableToTypeName(currentControllerType.FullName, TypeNameStyle.FullName));

                            if (isPathAlreadyDefinedInInheritanceHierarchy == false)
                            {
                                var operationDescription = new OpenApiOperationDescription
                                {
                                    Path      = httpPath,
                                    Method    = httpMethod,
                                    Operation = new OpenApiOperation
                                    {
                                        IsDeprecated = method.GetCustomAttribute <ObsoleteAttribute>() != null,
                                        OperationId  = GetOperationId(document, controllerType.Name, method, httpMethod)
                                    }
                                };

                                operations.Add(new Tuple <OpenApiOperationDescription, MethodInfo>(operationDescription, method));
                            }
                        }
                    }
                }

                currentControllerType = currentControllerType.GetTypeInfo().BaseType;
            }

            return(AddOperationDescriptionsToDocument(document, controllerType, operations, swaggerGenerator, schemaResolver));
        }
Esempio n. 9
0
        private OperationProcessorContext GetContext(Type controllerType, MethodInfo methodInfo)
        {
            var document             = new OpenApiDocument();
            var operationDescription = new OpenApiOperationDescription {
                Operation = new OpenApiOperation()
            };

            return(new OperationProcessorContext(document, operationDescription, controllerType, methodInfo, null, null, null, null, null));
        }
 /// <summary>
 /// Sets the IsNullableRaw property of parameters to null for OpenApi3 schemas.
 /// </summary>
 /// <param name="operationDescription">Operation to check.</param>
 /// <param name="schemaType">Schema type.</param>
 private void UpdateNullableRawOperationParameters(OpenApiOperationDescription operationDescription, SchemaType schemaType)
 {
     if (schemaType == SchemaType.OpenApi3)
     {
         foreach (OpenApiParameter openApiParameter in operationDescription.Operation.Parameters)
         {
             openApiParameter.IsNullableRaw = null;
         }
     }
 }
Esempio n. 11
0
        private static string GetPathExpression(OpenApiOperationDescription operation)
        {
            var pathExpression = operation.Path;

            if (pathExpression.StartsWith("/", StringComparison.InvariantCulture))
            {
                pathExpression = pathExpression.Substring(1);
            }

            pathExpression = pathExpression.Replace("{namespace}", "{namespaceParameter}");
            return(pathExpression);
        }
        private OperationProcessorContext GetContext(Type controllerType, MethodInfo methodInfo)
        {
            var document             = new OpenApiDocument();
            var operationDescription = new OpenApiOperationDescription {
                Operation = new OpenApiOperation()
            };
            var settings = new OpenApiDocumentGeneratorSettings {
                UseControllerSummaryAsTagDescription = true
            };

            return(new OperationProcessorContext(document, operationDescription, controllerType, methodInfo, null, null, null, settings, null));
        }
 private void RemoveUnusedPathParameters(OpenApiOperationDescription operationDescription, string httpPath)
 {
     operationDescription.Path = Regex.Replace(httpPath, "{(.*?)(:(([^/]*)?))?}", match =>
     {
         var parameterName = match.Groups[1].Value.TrimEnd('?');
         if (operationDescription.Operation.ActualParameters.Any(p => p.Kind == OpenApiParameterKind.Path && string.Equals(p.Name, parameterName, StringComparison.OrdinalIgnoreCase)))
         {
             return("{" + parameterName + "}");
         }
         return(string.Empty);
     }).TrimEnd('/');
 }
Esempio n. 14
0
 private void ProcessControllerSwaggerTagAttributes(OpenApiOperationDescription operationDescription, TypeInfo typeInfo)
 {
     foreach (var tagAttribute in typeInfo.GetCustomAttributes()
              .GetAssignableToTypeName("OpenApiTagAttribute", TypeNameStyle.Name)
              .Select(a => (dynamic)a))
     {
         if (operationDescription.Operation.Tags.All(t => t != tagAttribute.Name))
         {
             operationDescription.Operation.Tags.Add(tagAttribute.Name);
         }
     }
 }
Esempio n. 15
0
 /// <summary>Initializes a new instance of the <see cref="AspNetCoreOperationProcessorContext" /> class.</summary>
 /// <param name="document">The document.</param>
 /// <param name="operationDescription">The operation description.</param>
 /// <param name="controllerType">Type of the controller.</param>
 /// <param name="methodInfo">The method information.</param>
 /// <param name="swaggerGenerator">The swagger generator.</param>
 /// <param name="schemaResolver">The schema resolver.</param>
 /// <param name="settings">The sett</param>
 /// <param name="allOperationDescriptions">All operation descriptions.</param>
 /// <param name="schemaGenerator">The schema generator.</param>
 public AspNetCoreOperationProcessorContext(
     OpenApiDocument document,
     OpenApiOperationDescription operationDescription,
     Type controllerType,
     MethodInfo methodInfo,
     OpenApiDocumentGenerator swaggerGenerator,
     JsonSchemaGenerator schemaGenerator,
     JsonSchemaResolver schemaResolver,
     OpenApiDocumentGeneratorSettings settings,
     IList <OpenApiOperationDescription> allOperationDescriptions)
     : base(document, operationDescription, controllerType, methodInfo, swaggerGenerator, schemaGenerator, schemaResolver, settings, allOperationDescriptions)
 {
 }
Esempio n. 16
0
        /// <summary>
        /// Map ApiOperation to TypeScriptOperationModel
        /// </summary>
        /// <param name="openApiOperation"></param>
        /// <returns></returns>
        public virtual TypeScriptOperationModel GetOperationModelByApiOperation(
            OpenApiOperationDescription openApiOperation)
        {
            var operationModel =
                new TypeScriptOperationModel(openApiOperation.Operation, _clientGeneratorSettings,
                                             _typeScriptClientGenerator, _resolver);

            operationModel.ControllerName = _clientGeneratorSettings.OperationNameGenerator.GetClientName(
                _openApiDocument, openApiOperation.Path, openApiOperation.Method, openApiOperation.Operation);
            operationModel.Path          = openApiOperation.Path;
            operationModel.HttpMethod    = openApiOperation.Method;
            operationModel.OperationName = _clientGeneratorSettings.OperationNameGenerator.GetOperationName(
                _openApiDocument, openApiOperation.Path, openApiOperation.Method, openApiOperation.Operation);
            return(operationModel);
        }
        public async Task When_complex_type_with_nullable_primitive_query_parameter_exists_then_parameter_IsNullableRaw_is_null()
        {
            //// Arrange
            WebApiOpenApiDocumentGenerator generator = this.GetOpenApi3Generator();

            //// Act
            OpenApiDocument document = await generator.GenerateForControllerAsync <TestController>();

            OpenApiOperationDescription operationDescription = document.Operations.Single(o =>
                                                                                          o.Operation.OperationId.EndsWith(nameof(TestController.GetByReferenceTypeWithNullablePrimitiveType)));

            OpenApiOperation operation = operationDescription.Operation;

            //// Assert
            Assert.IsNull(operation.Parameters.Single().IsNullableRaw);
        }
Esempio n. 18
0
        private void ProcessSwaggerTagAttributes(OpenApiDocument document, OpenApiOperationDescription operationDescription, MethodInfo methodInfo)
        {
            foreach (var tagAttribute in methodInfo.GetCustomAttributes()
                     .GetAssignableToTypeName("SwaggerTagAttribute", TypeNameStyle.Name)
                     .Select(a => (dynamic)a))
            {
                if (operationDescription.Operation.Tags.All(t => t != tagAttribute.Name))
                {
                    operationDescription.Operation.Tags.Add(tagAttribute.Name);
                }

                if (ObjectExtensions.HasProperty(tagAttribute, "AddToDocument") && tagAttribute.AddToDocument)
                {
                    DocumentTagsProcessor.ProcessTagAttribute(document, tagAttribute);
                }
            }
        }
 private void UpdateConsumedTypes(OpenApiOperationDescription operationDescription)
 {
     if (operationDescription.Operation.ActualParameters.Any(p => p.Type == JsonObjectType.File))
     {
         operationDescription.Operation.Consumes = new List <string> {
             "multipart/form-data"
         }
     }
     ;
     else if (operationDescription.Operation.ActualParameters.Any(p => p.Kind == OpenApiParameterKind.FormData))
     {
         operationDescription.Operation.Consumes = new List <string>()
         {
             "application/x-www-form-urlencoded"
         }
     }
     ;
 }
Esempio n. 20
0
        /// <summary>Gets the security scopes for an operation.</summary>
        /// <param name="operationDescription">The operation description.</param>
        /// <param name="methodInfo">The method information.</param>
        /// <returns>The scopes.</returns>
        protected virtual IEnumerable <string> GetScopes(OpenApiOperationDescription operationDescription, MethodInfo methodInfo)
        {
            var allAttributes = methodInfo.GetCustomAttributes().Concat(
                methodInfo.DeclaringType.GetTypeInfo().GetCustomAttributes());

            var authorizeAttributes = allAttributes.Where(a => a.GetType().Name == "AuthorizeAttribute").ToList();

            if (!authorizeAttributes.Any())
            {
                return(Enumerable.Empty <string>());
            }

            return(authorizeAttributes
                   .Select(a => (dynamic)a)
                   .Where(a => a.Roles != null)
                   .SelectMany(a => ((string)a.Roles).Split(','))
                   .Distinct());
        }
Esempio n. 21
0
        private void ProcessControllerSwaggerTagsAttribute(OpenApiOperationDescription operationDescription, TypeInfo typeInfo)
        {
            dynamic tagsAttribute = typeInfo
                                    .GetCustomAttributes()
                                    .FirstAssignableToTypeNameOrDefault("OpenApiTagsAttribute", TypeNameStyle.Name);

            if (tagsAttribute != null)
            {
                var tags = ((string[])tagsAttribute.Tags).ToList();
                foreach (var tag in tags)
                {
                    if (operationDescription.Operation.Tags.All(t => t != tag))
                    {
                        operationDescription.Operation.Tags.Add(tag);
                    }
                }
            }
        }
Esempio n. 22
0
        private void AddOperation(Domain domain, OpenApiOperationDescription op, OpenApiDocument doc)
        {
            if (!OperationProducesBinary(op))
            {
                Log.Information("Adding operation {Path} to domain", op.Path);
                var parts       = DecomposeRoutePath(op.Path);
                var noun        = Util.CanonicalizeName(parts.noun);
                var relatedType = domain.Types.FirstOrDefault(t => Util.CanonicalizeName(t.Name) == noun);
                var domainOp    = new Operation {
                    Name = $"{ConvertApiStyleNameToStandardName(parts.noun)}_{ConvertApiStyleNameToStandardName(parts.verb)}", Namespace = domain.DefaultNamespace, RelatedType = relatedType
                };
                domainOp.Attributes            = new JObject();
                domainOp.Attributes.HttpMethod = op.Method;

                if (op.Method == "post" || op.Method == "put")
                {
                    domainOp.Attributes.changesData = true;
                    domainOp.Attributes.createsNew  = true; // don't do a 'select by Id' first
                }

                if (op.Method == "delete")
                {
                    domainOp.Attributes.isDelete = true;
                }

                PopulateNewOperationParameters(domain, op, doc, domainOp);

                if (op.Operation.ActualResponses.ContainsKey("200"))
                {
                    PopulateNewOperationResponse(domain, op, doc, domainOp);
                }
                else
                {
                    Log.Information("Operation {Path} does not define a successful response, so no domain operation will be added for it.", op.Path);
                }

                domain.Operations.Add(domainOp);
            }
            else
            {
                Log.Debug("OpenApi operation {Path} produces a file. We won't add operation information for it.", op.Path);
            }
        }
Esempio n. 23
0
        private void ApplyOpenApiBodyParameterAttribute(OpenApiOperationDescription operationDescription, MethodInfo methodInfo)
        {
            dynamic bodyParameterAttribute = methodInfo.GetCustomAttributes()
                                             .FirstAssignableToTypeNameOrDefault("OpenApiBodyParameterAttribute", TypeNameStyle.Name);

            if (bodyParameterAttribute != null)
            {
                if (operationDescription.Operation.RequestBody == null)
                {
                    operationDescription.Operation.RequestBody = new OpenApiRequestBody();
                }

                operationDescription.Operation.RequestBody.Content[bodyParameterAttribute.MimeType] = new OpenApiMediaType
                {
                    Schema = bodyParameterAttribute.MimeType == "application/json" ? JsonSchema.CreateAnySchema() : new JsonSchema
                    {
                        Type = JsonObjectType.File
                    }
                };
            }
        }
Esempio n. 24
0
        private bool GenerateForHandler(OpenApiDocument document, Type handlerType, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver)
        {
            var methodInfo = handlerType.GetMethod("Handle");
            var isQuery    = handlerType.IsAssignableToGenericType(typeof(IQueryRequestHandler <,>));

            var httpMethod = isQuery ? OpenApiOperationMethod.Get : OpenApiOperationMethod.Post;
            var httpPath   = $"/rpc/{GetRequestTypeFullName(methodInfo)}";

            var operationDescription = new OpenApiOperationDescription
            {
                Path      = httpPath,
                Method    = httpMethod,
                Operation = new OpenApiOperation
                {
                    IsDeprecated = methodInfo.GetCustomAttribute <ObsoleteAttribute>() != null,
                    OperationId  = GetOperationId(document, handlerType.Name)
                }
            };

            return(AddOperationDescriptionsToDocumentAsync(document, handlerType, (operationDescription, methodInfo), swaggerGenerator, schemaResolver));
        }
Esempio n. 25
0
        private void PopulateNewOperationParameters(Domain domain, OpenApiOperationDescription op, OpenApiDocument doc, Operation domainOp)
        {
            var index = 0;

            foreach (var apiParameter in op.Operation.ActualParameters)
            {
                var clrType = GetClrTypeForJsonSchemaType(apiParameter.Schema.Type);
                if (clrType == null)
                {
                    // TODO - find or create a domain type to match this
                }

                var parameter = new Parameter(domain, domainOp)
                {
                    Name = apiParameter.Name, ClrType = clrType, Order = index, Attributes = new JObject()
                };
                parameter.Attributes.userEditable = true;
                domainOp.Parameters.Add(parameter);
                index++;
                Log.Debug("Parameter: {param}", apiParameter);
            }
        }
        // TODO: remove asyncness as most NSwag operations have been converted to sync.
        private async Task <bool> RunOperationProcessorsAsync(OpenApiDocument document, Type staticAzureFunctionClassType, MethodInfo methodInfo,
                                                              OpenApiOperationDescription operationDescription, List <OpenApiOperationDescription> allOperations, OpenApiDocumentGenerator swaggerGenerator,
                                                              OpenApiSchemaResolver schemaResolver)
        {
            var context = new OperationProcessorContext(document, operationDescription, staticAzureFunctionClassType,
                                                        methodInfo, swaggerGenerator, Settings.SchemaGenerator, schemaResolver, Settings, allOperations);

            // 1. Run from settings
            foreach (var operationProcessor in Settings.OperationProcessors)
            {
                if (operationProcessor.Process(context) == false)
                {
                    return(false);
                }
            }


            // 2. Run from class attributes
            var operationProcessorAttribute = methodInfo.DeclaringType.GetTypeInfo()
                                              .GetCustomAttributes()
                                              // 3. Run from method attributes
                                              .Concat(methodInfo.GetCustomAttributes())
                                              .Where(a => a.GetType().IsAssignableToTypeName("SwaggerOperationProcessorAttribute", TypeNameStyle.Name));

            foreach (dynamic attribute in operationProcessorAttribute)
            {
                var operationProcessor = ObjectExtensions.HasProperty(attribute, "Parameters") ?
                                         (IOperationProcessor)Activator.CreateInstance(attribute.Type, attribute.Parameters) :
                                         (IOperationProcessor)Activator.CreateInstance(attribute.Type);

                if (operationProcessor.Process(context) == false)
                {
                    return(false);
                }
            }

            return(true);
        }
Esempio n. 27
0
        /// <summary>Initializes a new instance of the <see cref="OperationProcessorContext" /> class.</summary>
        /// <param name="document">The document.</param>
        /// <param name="operationDescription">The operation description.</param>
        /// <param name="controllerType">Type of the controller.</param>
        /// <param name="methodInfo">The method information.</param>
        /// <param name="openApiDocumentGenerator">The swagger generator.</param>
        /// <param name="schemaResolver">The schema resolver.</param>
        /// <param name="settings">The settings.</param>
        /// <param name="allOperationDescriptions">All operation descriptions.</param>
        /// <param name="schemaGenerator">The schema generator.</param>
        public OperationProcessorContext(
            OpenApiDocument document,
            OpenApiOperationDescription operationDescription,
            Type controllerType,
            MethodInfo methodInfo,
            OpenApiDocumentGenerator openApiDocumentGenerator,
            JsonSchemaGenerator schemaGenerator,
            JsonSchemaResolver schemaResolver,
            OpenApiDocumentGeneratorSettings settings,
            IList <OpenApiOperationDescription> allOperationDescriptions)
        {
            Document = document;

            OperationDescription = operationDescription;
            ControllerType       = controllerType;
            MethodInfo           = methodInfo;

            DocumentGenerator = openApiDocumentGenerator;
            SchemaGenerator   = schemaGenerator;
            SchemaResolver    = schemaResolver;

            Settings = settings;
            AllOperationDescriptions = allOperationDescriptions;
        }
Esempio n. 28
0
        private List <Type> GenerateApiGroups(
            OpenApiDocument document,
            IGrouping <Type, Tuple <ApiDescription, ActionDescriptor> >[] apiGroups,
            OpenApiSchemaResolver schemaResolver)
        {
            var usedControllerTypes = new List <Type>();
            var swaggerGenerator    = new OpenApiDocumentGenerator(Settings, schemaResolver);

            var allOperations = new List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> >();

            foreach (var apiGroup in apiGroups)
            {
                var controllerType = apiGroup.Key;

                var hasIgnoreAttribute = controllerType != null && controllerType
                                         .GetTypeInfo()
                                         .GetCustomAttributes()
                                         .GetAssignableToTypeName("SwaggerIgnoreAttribute", TypeNameStyle.Name)
                                         .Any();

                if (!hasIgnoreAttribute)
                {
                    var operations = new List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> >();
                    foreach (var item in apiGroup)
                    {
                        var apiDescription = item.Item1;
                        if (apiDescription.RelativePath == null)
                        {
                            continue;
                        }

                        var method = (item.Item2 as ControllerActionDescriptor)?.MethodInfo;
                        if (method != null)
                        {
                            var actionHasIgnoreAttribute = method.GetCustomAttributes().GetAssignableToTypeName("SwaggerIgnoreAttribute", TypeNameStyle.Name).Any();
                            if (actionHasIgnoreAttribute)
                            {
                                continue;
                            }
                        }

                        var path = apiDescription.RelativePath;
                        if (!path.StartsWith("/", StringComparison.Ordinal))
                        {
                            path = "/" + path;
                        }

                        var httpMethod = apiDescription.HttpMethod?.ToLowerInvariant() ?? (apiDescription.ParameterDescriptions.Where(p =>
                        {
                            return(p.Source == Microsoft.AspNetCore.Mvc.ModelBinding.BindingSource.Body);
                        }).Count() > 0 ? OpenApiOperationMethod.Post : OpenApiOperationMethod.Get);

                        var operationDescription = new OpenApiOperationDescription
                        {
                            Path      = path,
                            Method    = httpMethod,
                            Operation = new OpenApiOperation
                            {
                                IsDeprecated = IsOperationDeprecated(item.Item1, apiDescription.ActionDescriptor, method),
                                OperationId  = GetOperationId(document, apiDescription, method, httpMethod),
                                Consumes     = apiDescription.SupportedRequestFormats
                                               .Select(f => f.MediaType)
                                               .Distinct()
                                               .ToList(),
                                Produces = apiDescription.SupportedResponseTypes
                                           .SelectMany(t => t.ApiResponseFormats.Select(f => f.MediaType))
                                           .Distinct()
                                           .ToList()
                            }
                        };

                        operations.Add(new Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo>(operationDescription, apiDescription, method));
                    }

                    var addedOperations = AddOperationDescriptionsToDocument(document, controllerType, operations, swaggerGenerator, schemaResolver);
                    if (addedOperations.Any() && apiGroup.Key != null)
                    {
                        usedControllerTypes.Add(apiGroup.Key);
                    }

                    allOperations.AddRange(addedOperations);
                }
            }

            UpdateConsumesAndProduces(document, allOperations);
            return(usedControllerTypes);
        }
        private List <Type> GenerateForControllers(
            OpenApiDocument document,
            IGrouping <Type, Tuple <ApiDescription, ControllerActionDescriptor> >[] apiGroups,
            OpenApiSchemaResolver schemaResolver)
        {
            var usedControllerTypes = new List <Type>();
            var swaggerGenerator    = new OpenApiDocumentGenerator(Settings, schemaResolver);

            var allOperations = new List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> >();

            foreach (var controllerApiDescriptionGroup in apiGroups)
            {
                var controllerType = controllerApiDescriptionGroup.Key;

                var hasIgnoreAttribute = controllerType.GetTypeInfo()
                                         .GetCustomAttributes()
                                         .GetAssignableToTypeName("SwaggerIgnoreAttribute", TypeNameStyle.Name)
                                         .Any();

                if (!hasIgnoreAttribute)
                {
                    var operations = new List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> >();
                    foreach (var item in controllerApiDescriptionGroup)
                    {
                        var apiDescription = item.Item1;
                        var method         = item.Item2.MethodInfo;

                        var actionHasIgnoreAttribute = method.GetCustomAttributes().GetAssignableToTypeName("SwaggerIgnoreAttribute", TypeNameStyle.Name).Any();
                        if (actionHasIgnoreAttribute)
                        {
                            continue;
                        }

                        var path = apiDescription.RelativePath;
                        if (!path.StartsWith("/", StringComparison.Ordinal))
                        {
                            path = "/" + path;
                        }

                        var controllerActionDescriptor = (ControllerActionDescriptor)apiDescription.ActionDescriptor;
                        var httpMethod = apiDescription.HttpMethod?.ToLowerInvariant() ?? OpenApiOperationMethod.Get;

                        var operationDescription = new OpenApiOperationDescription
                        {
                            Path      = path,
                            Method    = httpMethod,
                            Operation = new OpenApiOperation
                            {
                                IsDeprecated = method.GetCustomAttribute <ObsoleteAttribute>() != null,
                                OperationId  = GetOperationId(document, controllerActionDescriptor, method),
                                Consumes     = apiDescription.SupportedRequestFormats
                                               .Select(f => f.MediaType)
                                               .Distinct()
                                               .ToList(),
                                Produces = apiDescription.SupportedResponseTypes
                                           .SelectMany(t => t.ApiResponseFormats.Select(f => f.MediaType))
                                           .Distinct()
                                           .ToList()
                            }
                        };

                        operations.Add(new Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo>(operationDescription, apiDescription, method));
                    }

                    var addedOperations = AddOperationDescriptionsToDocument(document, controllerType, operations, swaggerGenerator, schemaResolver);
                    if (addedOperations.Any())
                    {
                        usedControllerTypes.Add(controllerApiDescriptionGroup.Key);
                    }

                    allOperations.AddRange(addedOperations);
                }
            }

            UpdateConsumesAndProduces(document, allOperations);
            return(usedControllerTypes);
        }
Esempio n. 30
0
        private (Operation operation, MatchType matchType) FindMatchingDomainOperation(Domain domain, OpenApiOperationDescription op, OpenApiDocument doc)
        {
            string noun = null;
            string verb = null;

            try
            {
                var routeParts = DecomposeRoutePath(op.Path);
                noun = Util.CanonicalizeName(routeParts.noun);
                verb = Util.CanonicalizeName(routeParts.verb);
            }
            catch (FormatException)
            {
                Log.Warning("Api Operation path {Path} was not of the expected format. Expected /api/[noun]/[verb]", op.Path);
                return(null, MatchType.Error);
            }

            var nameMatch = domain.Operations.Where(dmnOp => dmnOp.RelatedType != null && Util.CanonicalizeName(dmnOp.BareName) == verb && Util.CanonicalizeName(dmnOp.RelatedType.Name) == noun);

            if (nameMatch.Any())
            {
                if (nameMatch.Count() == 1)
                {
                    var domainOp = nameMatch.First();
                    Log.Debug("API operation {Path} matched {OperationName} by name", op.Path, domainOp.Name);
                    if (ParametersMatch(domainOp, domain, op, doc) && ReturnTypesMatch(domainOp, domain, op, doc))
                    {
                        return(domainOp, MatchType.Exact);
                    }
                    else
                    {
                        return(domainOp, MatchType.Replace);
                    }
                }
                else
                {
                    // TODO - find nearest match?
                    Log.Error("There were multiple operations that matched API operation {OperationName} by name.", op.Path);
                    return(null, MatchType.Error);
                }
            }
            return(null, MatchType.None);
        }