Пример #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);
        }
        /// <summary>Generates a Swagger specification for the given <see cref="ApiDescriptionGroupCollection"/>.</summary>
        /// <param name="apiDescriptionGroups">The <see cref="ApiDescriptionGroupCollection"/>.</param>
        /// <returns>The <see cref="OpenApiDocument" />.</returns>
        /// <exception cref="InvalidOperationException">The operation has more than one body parameter.</exception>
        public async Task <OpenApiDocument> GenerateAsync(ApiDescriptionGroupCollection apiDescriptionGroups)
        {
            var apiDescriptions = apiDescriptionGroups.Items
                                  .Where(group =>
                                         Settings.ApiGroupNames == null ||
                                         Settings.ApiGroupNames.Length == 0 ||
                                         Settings.ApiGroupNames.Contains(group.GroupName))
                                  .SelectMany(g => g.Items)
                                  .Where(apiDescription => apiDescription.ActionDescriptor is ControllerActionDescriptor)
                                  .ToArray();

            var document = await CreateDocumentAsync().ConfigureAwait(false);

            var schemaResolver = new OpenApiSchemaResolver(document, Settings);

            var apiGroups = apiDescriptions
                            .Select(apiDescription => new Tuple <ApiDescription, ControllerActionDescriptor>(apiDescription, (ControllerActionDescriptor)apiDescription.ActionDescriptor))
                            .GroupBy(item => item.Item2.ControllerTypeInfo.AsType())
                            .ToArray();

            var usedControllerTypes = GenerateForControllers(document, apiGroups, schemaResolver);

            document.GenerateOperationIds();

            var controllerTypes = apiGroups.Select(k => k.Key).ToArray();

            foreach (var processor in Settings.DocumentProcessors)
            {
                processor.Process(new DocumentProcessorContext(document, controllerTypes, usedControllerTypes, schemaResolver, Settings.SchemaGenerator, Settings));
            }

            Settings.PostProcess?.Invoke(document);
            return(document);
        }
        /// <summary>
        /// Generates Swagger document for the specified Azure Function classes, including only the listed Functions.
        /// </summary>
        /// <param name="azureFunctionClassTypes">The Azure Function classes (static classes)</param>
        /// <param name="functionNames">The function names (defined by FunctionNameAttribute)</param>
        /// <returns>The generated Swagger document</returns>
        public async Task <OpenApiDocument> GenerateForAzureFunctionClassesAsync(IEnumerable <Type> azureFunctionClassTypes,
                                                                                 IList <string> functionNames)
        {
            var document = await CreateDocumentAsync().ConfigureAwait(false);

            var schemaResolver = new OpenApiSchemaResolver(document, Settings);
            var usedAzureFunctionClassTypes = new List <Type>();

            foreach (var azureFunctionClassType in azureFunctionClassTypes)
            {
                var generator  = new OpenApiDocumentGenerator(Settings, schemaResolver);
                var isIncluded = await GenerateForAzureFunctionClassAsync(document, azureFunctionClassType,
                                                                          generator, schemaResolver, functionNames);

                if (isIncluded)
                {
                    usedAzureFunctionClassTypes.Add(azureFunctionClassType);
                }
            }

            document.GenerateOperationIds();

            foreach (var processor in Settings.DocumentProcessors)
            {
                processor.Process(new DocumentProcessorContext(document, azureFunctionClassTypes,
                                                               usedAzureFunctionClassTypes, schemaResolver, Settings.SchemaGenerator, Settings));
            }

            return(document);
        }
Пример #4
0
        /// <summary>Generates a Swagger specification for the given controller types.</summary>
        /// <param name="controllerTypes">The types of the controller.</param>
        /// <returns>The <see cref="OpenApiDocument" />.</returns>
        /// <exception cref="InvalidOperationException">The operation has more than one body parameter.</exception>
        public async Task <OpenApiDocument> GenerateForControllersAsync(IEnumerable <Type> controllerTypes)
        {
            var document = await CreateDocumentAsync().ConfigureAwait(false);

            var schemaResolver = new OpenApiSchemaResolver(document, Settings);

            var usedControllerTypes = new List <Type>();

            foreach (var controllerType in controllerTypes)
            {
                var generator  = new OpenApiDocumentGenerator(Settings, schemaResolver);
                var isIncluded = GenerateForController(document, controllerType, generator, schemaResolver);
                if (isIncluded)
                {
                    usedControllerTypes.Add(controllerType);
                }
            }

            document.GenerateOperationIds();

            foreach (var processor in Settings.DocumentProcessors)
            {
                processor.Process(new DocumentProcessorContext(document, controllerTypes,
                                                               usedControllerTypes, schemaResolver, Settings.SchemaGenerator, Settings));
            }

            return(document);
        }
Пример #5
0
        public void When_generating_multiple_types_then_they_are_appended_to_the_definitions()
        {
            //// Arrange
            var classNames = new[]
            {
                "NSwag.Generation.WebApi.Tests.B",
                "NSwag.Generation.WebApi.Tests.C"
            };

            //// Act
            var document       = new OpenApiDocument();
            var settings       = new JsonSchemaGeneratorSettings();
            var schemaResolver = new OpenApiSchemaResolver(document, settings);
            var generator      = new JsonSchemaGenerator(settings);

            foreach (var className in classNames)
            {
                var type = typeof(TypesToSwaggerTests).Assembly.GetType(className);
                generator.Generate(type, schemaResolver);
            }
            var json = document.ToJson();

            //// Assert
            Assert.IsNotNull(json);
            Assert.AreEqual(2, document.Definitions.Count);
        }
Пример #6
0
        protected override async Task <string> RunIsolatedAsync(AssemblyLoader.AssemblyLoader assemblyLoader)
        {
            var document       = new OpenApiDocument();
            var generator      = new JsonSchemaGenerator(Settings);
            var schemaResolver = new OpenApiSchemaResolver(document, Settings);

#if FullNet
            var assemblies = PathUtilities.ExpandFileWildcards(AssemblyPaths)
                             .Select(path => Assembly.LoadFrom(path)).ToArray();
#else
            var currentDirectory = DynamicApis.DirectoryGetCurrentDirectory();
            var assemblies       = PathUtilities.ExpandFileWildcards(AssemblyPaths)
                                   .Select(path => assemblyLoader.Context.LoadFromAssemblyPath(PathUtilities.MakeAbsolutePath(path, currentDirectory))).ToArray();
#endif

            var allExportedClassNames = assemblies.SelectMany(a => a.ExportedTypes).Select(t => t.FullName).ToList();
            var matchedClassNames     = ClassNames
                                        .SelectMany(n => PathUtilities.FindWildcardMatches(n, allExportedClassNames, '.'))
                                        .Distinct();

            foreach (var className in matchedClassNames)
            {
                var type = assemblies.Select(a => a.GetType(className)).FirstOrDefault(t => t != null);
                generator.Generate(type, schemaResolver);
            }

            return(document.ToJson(OutputType));
        }
Пример #7
0
        public async Task <OpenApiDocument> GenerateDocument(Assembly assembly)
        {
            var document = await CreateDocumentAsync().ConfigureAwait(false);

            var schemaResolver = new OpenApiSchemaResolver(document, Settings);

            var handlerTypes     = GetAllHandlerTypes(assembly);
            var usedHandlerTypes = new List <Type>();

            foreach (var handlerType in handlerTypes)
            {
                var generator  = new OpenApiDocumentGenerator(Settings, schemaResolver);
                var isIncluded = GenerateForHandler(document, handlerType, generator, schemaResolver);
                if (isIncluded)
                {
                    usedHandlerTypes.Add(handlerType);
                }
            }

            document.GenerateOperationIds();

            foreach (var processor in Settings.DocumentProcessors)
            {
                processor.Process(new DocumentProcessorContext(document, handlerTypes,
                                                               usedHandlerTypes, schemaResolver, Settings.SchemaGenerator, Settings));
            }

            return(document);
        }
Пример #8
0
        internal Builder(IAppEntity app,
                         OpenApiDocument document,
                         OpenApiSchemaResolver schemaResolver,
                         OpenApiSchemaGenerator schemaGenerator)
        {
            Document = document;

            AppName = app.Name;

            ChangeStatusSchema = schemaGenerator.GenerateWithReference <JsonSchema>(typeof(ChangeStatusDto).ToContextualType(), schemaResolver);
        }
Пример #9
0
        private static List <OpenApiDocument> GetOpenApiDocumentSepareted(JsonSchemaGeneratorSettings settings, Assembly[] assemblies, List <string> classNames)
        {
            List <OpenApiDocument> result = new List <OpenApiDocument>();

            foreach (var className in classNames)
            {
                var document       = new OpenApiDocument();
                var generator      = new JsonSchemaGenerator(settings);
                var schemaResolver = new OpenApiSchemaResolver(document, settings);
                var type           = assemblies.Select(a => a.GetType(className)).FirstOrDefault(t => t != null);
                generator.Generate(type, schemaResolver);
                result.Add(document);
            }

            return(result);
        }
Пример #10
0
        public async Task <OpenApiDocument> GenerateAsync(HttpContext httpContext, IAppEntity app, IEnumerable <ISchemaEntity> schemas, bool flat)
        {
            var document = CreateApiDocument(httpContext, app);

            var schemaResolver = new OpenApiSchemaResolver(document, schemaSettings);

            requestCache.AddDependency(app.UniqueId, app.Version);

            foreach (var schema in schemas)
            {
                requestCache.AddDependency(schema.UniqueId, schema.Version);
            }

            var builder = new Builder(app, document, schemaResolver, schemaGenerator);

            var validSchemas =
                schemas.Where(x =>
                              x.SchemaDef.IsPublished &&
                              x.SchemaDef.Type != SchemaDefType.Component &&
                              x.SchemaDef.Fields.Count > 0);

            var partitionResolver = app.PartitionResolver();

            foreach (var schema in validSchemas)
            {
                var components = await appProvider.GetComponentsAsync(schema, httpContext.RequestAborted);

                GenerateSchemaOperations(builder.Schema(schema.SchemaDef, partitionResolver, components, flat));
            }

            GenerateSharedOperations(builder.Shared());

            var context =
                new DocumentProcessorContext(document,
                                             Enumerable.Empty <Type>(),
                                             Enumerable.Empty <Type>(),
                                             schemaResolver,
                                             schemaGenerator,
                                             schemaSettings);

            foreach (var processor in schemaSettings.DocumentProcessors)
            {
                processor.Process(context);
            }

            return(document);
        }
Пример #11
0
        private List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> > AddOperationDescriptionsToDocument(
            OpenApiDocument document, Type controllerType,
            List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> > operations,
            OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver)
        {
            var addedOperations = new List <Tuple <OpenApiOperationDescription, ApiDescription, MethodInfo> >();
            var allOperations   = new List <OpenApiOperationDescription>(operations.Count);

            allOperations.AddRange(operations.Select(t => t.Item1));

            foreach (var tuple in operations)
            {
                var operation      = tuple.Item1;
                var apiDescription = tuple.Item2;
                var method         = tuple.Item3;

                var addOperation = RunOperationProcessors(
                    document,
                    apiDescription,
                    controllerType,
                    method,
                    operation,
                    allOperations,
                    swaggerGenerator,
                    schemaResolver);

                if (addOperation)
                {
                    var path = operation.Path.Replace("//", "/");
                    if (!document.Paths.TryGetValue(path, out var pathItem))
                    {
                        document.Paths[path] = pathItem = new OpenApiPathItem();
                    }

                    if (pathItem.ContainsKey(operation.Method))
                    {
                        throw new InvalidOperationException($"The method '{operation.Method}' on path '{path}' is registered multiple times.");
                    }

                    pathItem[operation.Method] = operation.Operation;
                    addedOperations.Add(tuple);
                }
            }

            return(addedOperations);
        }
Пример #12
0
        private static OpenApiDocument GetOpenApiDocument(JsonSchemaGeneratorSettings settings, Assembly[] assemblies, List <string> classNames)
        {
            var document       = new OpenApiDocument();
            var generator      = new JsonSchemaGenerator(settings);
            var schemaResolver = new OpenApiSchemaResolver(document, settings);

            //IEnumerable<string> matchedClassNames = ClassNames
            //    .SelectMany(n => PathUtilities.FindWildcardMatches(n, allExportedClassNames, '.'))
            //    .Distinct();

            foreach (var className in classNames)
            {
                var type = assemblies.Select(a => a.GetType(className)).FirstOrDefault(t => t != null);
                generator.Generate(type, schemaResolver);
            }

            //SchemaType outputType = SchemaType.Swagger2;
            //return document.ToJson(outputType);

            return(document);
        }
Пример #13
0
        public OpenApiDocument Generate(HttpContext httpContext, IAppEntity app, IEnumerable <ISchemaEntity> schemas, bool flat = false)
        {
            var document = CreateApiDocument(httpContext, app);

            var schemaResolver = new OpenApiSchemaResolver(document, schemaSettings);

            requestCache.AddDependency(app.UniqueId, app.Version);

            var builder = new Builder(
                app,
                document,
                schemaResolver,
                schemaGenerator);

            foreach (var schema in schemas.Where(x => x.SchemaDef.IsPublished))
            {
                requestCache.AddDependency(schema.UniqueId, schema.Version);

                GenerateSchemaOperations(builder.Schema(schema.SchemaDef, flat));
            }

            GenerateSharedOperations(builder.Shared());

            var context =
                new DocumentProcessorContext(document,
                                             Enumerable.Empty <Type>(),
                                             Enumerable.Empty <Type>(),
                                             schemaResolver,
                                             schemaGenerator,
                                             schemaSettings);

            foreach (var processor in schemaSettings.DocumentProcessors)
            {
                processor.Process(context);
            }

            return(document);
        }
        // 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);
        }
        private async Task <bool> AddOperationDescriptionsToDocumentAsync(OpenApiDocument document, Type staticAzureFunctionClassType,
                                                                          List <Tuple <OpenApiOperationDescription, MethodInfo> > operations, OpenApiDocumentGenerator swaggerGenerator,
                                                                          OpenApiSchemaResolver schemaResolver)
        {
            var addedOperations = 0;
            var allOps          = operations.Select(t => t.Item1).ToList();

            foreach (var o in operations)
            {
                var operation = o.Item1;
                var method    = o.Item2;

                var addOperation = await RunOperationProcessorsAsync(document, staticAzureFunctionClassType, method,
                                                                     operation, allOps, swaggerGenerator, schemaResolver);

                if (addOperation)
                {
                    var path = operation.Path.Replace("//", "/");

                    if (!document.Paths.ContainsKey(path))
                    {
                        document.Paths[path] = new OpenApiPathItem();
                    }

                    if (document.Paths[path].ContainsKey(operation.Method))
                    {
                        throw new InvalidOperationException("The method '" + operation.Method + "' on path '" + path + "' is registered multiple times");
                    }

                    document.Paths[path][operation.Method] = operation.Operation;
                    addedOperations++;
                }
            }

            return(addedOperations > 0);
        }
        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 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);
        }
        private bool AddOperationDescriptionsToDocument(OpenApiDocument document, Type controllerType, List <Tuple <OpenApiOperationDescription, MethodInfo> > operations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver)
        {
            var addedOperations = 0;
            var allOperation    = operations.Select(t => t.Item1).ToList();

            foreach (var tuple in operations)
            {
                var operation = tuple.Item1;
                var method    = tuple.Item2;

                var addOperation = RunOperationProcessors(document, controllerType, method, operation, allOperation, swaggerGenerator, schemaResolver);
                if (addOperation)
                {
                    var path = operation.Path.Replace("//", "/");

                    // iiQ Custom
                    // .. Prevents "The method 'get' on path '/v1.0' is registered multiple times" exception
                    // .. Also guards for root pathed URLs such as "/v1.0" since all URLs are versioned in iiQ
                    if (path.Split(new char[] { '/' }).Length <= 2)
                    {
                        continue;
                    }

                    if (!document.Paths.ContainsKey(path))
                    {
                        document.Paths[path] = new OpenApiPathItem();
                    }

                    if (document.Paths[path].ContainsKey(operation.Method))
                    {
                        throw new InvalidOperationException("The method '" + operation.Method + "' on path '" + path + "' is registered multiple times " +
                                                            "(check the DefaultUrlTemplate setting [default for Web API: 'api/{controller}/{id}'; for MVC projects: '{controller}/{action}/{id?}']).");
                    }

                    document.Paths[path][operation.Method] = operation.Operation;
                    addedOperations++;
                }
            }

            return(addedOperations > 0);
        }
Пример #19
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));
        }
Пример #20
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);
        }
Пример #21
0
        private bool AddOperationDescriptionsToDocument(OpenApiDocument document, Type controllerType, List <Tuple <OpenApiOperationDescription, MethodInfo> > operations, OpenApiDocumentGenerator swaggerGenerator, OpenApiSchemaResolver schemaResolver)
        {
            var addedOperations = 0;
            var allOperation    = operations.Select(t => t.Item1).ToList();

            foreach (var tuple in operations)
            {
                var operation = tuple.Item1;
                var method    = tuple.Item2;

                var addOperation = RunOperationProcessors(document, controllerType, method, operation, allOperation, swaggerGenerator, schemaResolver);
                if (addOperation)
                {
                    var path = operation.Path.Replace("//", "/");

                    if (!document.Paths.ContainsKey(path))
                    {
                        document.Paths[path] = new OpenApiPathItem();
                    }

                    if (document.Paths[path].ContainsKey(operation.Method))
                    {
                        throw new InvalidOperationException("The method '" + operation.Method + "' on path '" + path + "' is registered multiple times " +
                                                            "(check the DefaultUrlTemplate setting [default for Web API: 'api/{controller}/{id}'; for MVC projects: '{controller}/{action}/{id?}']).");
                    }

                    document.Paths[path][operation.Method] = operation.Operation;
                    addedOperations++;
                }
            }

            return(addedOperations > 0);
        }
Пример #22
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));
        }