Example #1
0
        public static void EnableMultiVersionWebApiSwaggerWithUI(this HttpConfiguration httpConfiguration,
                                                                 Action <SwaggerDocsConfig> customizeSwagger        = null,
                                                                 Action <SwaggerUiConfig> customizeSwaggerUi        = null,
                                                                 Action <VersionedApiExplorer> customizeApiExplorer = null)
        {
            httpConfiguration.Properties.TryAdd("MultiVersionSwaggerConfiguration", new Action(() =>
            {
                VersionedApiExplorer apiExplorer = httpConfiguration.AddVersionedApiExplorer(options =>
                {
                    options.GroupNameFormat           = "'v'VVV";
                    options.SubstituteApiVersionInUrl = true;
                });

                customizeApiExplorer?.Invoke(apiExplorer);

                httpConfiguration.EnableSwagger("{apiVersion}/swagger", swagger =>
                {
                    swagger.MultipleApiVersions((apiDescription, version) => apiDescription.GetGroupName() == version,
                                                info =>
                    {
                        foreach (ApiDescriptionGroup group in apiExplorer.ApiDescriptions)
                        {
                            info.Version(group.Name, $"API {group.ApiVersion}");
                        }
                    });

                    swagger.ApplyDefaultApiConfig(httpConfiguration);

                    customizeSwagger?.Invoke(swagger);
                }).EnableBitSwaggerUi(swaggerUi => customizeSwaggerUi?.Invoke(swaggerUi));
            }));
        }
        public static void EnableMultiVersionWebApiSwaggerWithUI(this HttpConfiguration httpConfiguration,
                                                                 Action <SwaggerDocsConfig>?customizeSwagger        = null,
                                                                 Action <SwaggerUiConfig>?customizeSwaggerUi        = null,
                                                                 Action <VersionedApiExplorer>?customizeApiExplorer = null)
        {
            if (httpConfiguration == null)
            {
                throw new ArgumentNullException(nameof(httpConfiguration));
            }

            httpConfiguration.Properties.TryAdd("MultiVersionSwaggerConfiguration", new Action(() =>
            {
                VersionedApiExplorer apiExplorer = ((WebApiExplorerFactory)httpConfiguration.DependencyResolver.GetService(typeof(WebApiExplorerFactory)))(httpConfiguration);

                customizeApiExplorer?.Invoke(apiExplorer);

                httpConfiguration.EnableSwagger("{apiVersion}/swagger", swagger =>
                {
                    swagger.MultipleApiVersions((apiDescription, version) => apiDescription.GetGroupName() == version,
                                                info =>
                    {
                        foreach (ApiDescriptionGroup group in apiExplorer.ApiDescriptions)
                        {
                            info.Version(group.Name, $"API {group.ApiVersion}");
                        }
                    });

                    swagger.ApplyDefaultApiConfig(httpConfiguration);

                    customizeSwagger?.Invoke(swagger);
                }).EnableBitSwaggerUi(swaggerUi => customizeSwaggerUi?.Invoke(swaggerUi));
            }));
        }
Example #3
0
        /// <summary>
        /// Adds or replaces the configured <see cref="IApiExplorer">API explorer</see> with an implementation that supports API versioning.
        /// </summary>
        /// <param name="configuration">The <see cref="HttpConfiguration">configuration</see> used to add the API explorer.</param>
        /// <returns>The newly registered <see cref="VersionedApiExplorer">versioned API explorer</see>.</returns>
        /// <remarks>This method always replaces the <see cref="IApiExplorer"/> with a new instance of <see cref="VersionedApiExplorer"/>.</remarks>
        public static VersionedApiExplorer AddVersionedApiExplorer(this HttpConfiguration configuration)
        {
            Arg.NotNull(configuration, nameof(configuration));
            Contract.Ensures(Contract.Result <VersionedApiExplorer>() != null);

            var apiExplorer = new VersionedApiExplorer(configuration);

            configuration.Services.Replace(typeof(IApiExplorer), apiExplorer);
            return(apiExplorer);
        }
        static void BuildInfo(VersionInfoBuilder builder, VersionedApiExplorer explorer)
        {
            foreach (var group in explorer.ApiDescriptions)
            {
                var description = "Custom attribute example";

                if (group.IsDeprecated)
                {
                    description += " (Deprecated)";
                }

                builder.Version(group.Name, $"Custom attribute example - {group.ApiVersion}");
            }
        }
        public static VersionedApiExplorer WebApiExplorerFactory(HttpConfiguration webApiConfiguration)
        {
            if (webApiConfiguration == null)
            {
                throw new ArgumentNullException(nameof(webApiConfiguration));
            }

            VersionedApiExplorer apiExplorer = webApiConfiguration.AddVersionedApiExplorer(options =>
            {
                options.GroupNameFormat           = "'v'VVV";
                options.SubstituteApiVersionInUrl = true;
            });

            return(apiExplorer);
        }
Example #6
0
        /// <summary>
        /// Register swagger.
        /// </summary>
        /// <param name="configuration">Web API configuration.</param>
        /// <param name="apiExplorer">Web API explorer.</param>
        private static void RegisterSwagger(this HttpConfiguration configuration, VersionedApiExplorer apiExplorer)
        {
            configuration.EnableSwagger(
                "{apiVersion}/swagger",
                swagger =>
            {
                swagger.MultipleApiVersions(
                    (apiDescription, version) => apiDescription.GetGroupName() == version,
                    info =>
                {
                    foreach (var group in apiExplorer.ApiDescriptions)
                    {
                        var description = "Simple Web API description.";

                        if (group.IsDeprecated)
                        {
                            description += " This Web API version has been deprecated.";
                        }

                        info.Version(group.Name, $"Simple Web API {group.ApiVersion}")
                        .Contact(c => c.Name("John Smith").Email("*****@*****.**"))
                        .License(l => l.Name("MIT").Url("https://opensource.org/licenses/MIT"))
                        .Description(description)
                        .TermsOfService("Shareware");
                    }
                });
                swagger.PrettyPrint();
                swagger.DescribeAllEnumsAsStrings();
                swagger.Schemes(new[] { "http", "https" });
                swagger.IncludeAllXmlComments(typeof(WebApiConfig).Assembly, AppDomain.CurrentDomain.BaseDirectory);
            })
            .EnableSwaggerUi(swagger =>
            {
                swagger.DocumentTitle("Simple Web API");
                swagger.CssTheme("theme-flattop-css");
                swagger.EnableDiscoveryUrlSelector();
            });
        }
Example #7
0
        public static SwaggerDocsConfig VersioningSwaggerDoc(this SwaggerDocsConfig config,
                                                             VersionedApiExplorer apiExplorer, string docTitleFormat, string versionParamName)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            if (apiExplorer == null)
            {
                throw new ArgumentNullException(nameof(apiExplorer));
            }

            if (string.IsNullOrWhiteSpace(docTitleFormat))
            {
                throw new ArgumentNullException(nameof(docTitleFormat));
            }

            if (string.IsNullOrWhiteSpace(versionParamName))
            {
                throw new ArgumentNullException(nameof(versionParamName));
            }

            config.MultipleApiVersions(
                (apiDescription, version) => apiDescription.GetGroupName() == version,
                info =>
            {
                foreach (var group in apiExplorer.ApiDescriptions)
                {
                    info.Version(group.Name, string.Format(docTitleFormat, group.ApiVersion));
                }
            });

            config.OperationFilter(() => new RemoveVersionParameters(versionParamName));
            config.DocumentFilter(() => new SetVersionInPaths(versionParamName));

            return(config);
        }
        /// <summary>
        /// Setups the documentation.
        /// </summary>
        /// <param name="configuration">The configuration.</param>
        /// <param name="apiExplorer">The API explorer.</param>
        private static void SetupDocumentation(this HttpConfiguration configuration, VersionedApiExplorer apiExplorer)
        {
            const string SWAGGER_PATH_PREFIX = "{" + RouteConstants.API_VERSION_FIELD + "}/swagger";

            var swaggerConfiguration = configuration.EnableSwagger(SWAGGER_PATH_PREFIX, swaggerDocConfig =>
            {
                swaggerDocConfig.MultipleApiVersions(
                    (apiDescription, version) => apiDescription.GetGroupName() == version,
                    info =>
                {
                    if (apiExplorer.ApiDescriptions == null)
                    {
                        return;
                    }

                    foreach (var group in apiExplorer.ApiDescriptions)
                    {
                        var description = string.Empty;

                        if (group.IsDeprecated)
                        {
                            description += "This Service version has been deprecated.";
                        }

                        info.Version(group.Name, $"Version {group.ApiVersion}").Description(description);
                    }
                }
                    );

                swaggerDocConfig.Schemes(new[] { "http", "https" });
                swaggerDocConfig.PrettyPrint();
                swaggerDocConfig.DescribeAllEnumsAsStrings();
                swaggerDocConfig.IgnoreObsoleteActions();
                swaggerDocConfig.IgnoreObsoleteProperties();

                swaggerDocConfig.OperationFilter <SwaggerConsumesFilter>();
                swaggerDocConfig.OperationFilter <SwaggerProducesFilter>();
                swaggerDocConfig.OperationFilter <SwaggerUploadOperationFilter>();
                swaggerDocConfig.OperationFilter <SwaggerSecurityTypeAttributeFilter>();

                swaggerDocConfig.DocumentFilter <SwaggerMethodOrderingFilter>();
                swaggerDocConfig.DocumentFilter <SwaggerOperationOrderingFilter>();

                var basePath = $"{AppDomain.CurrentDomain.BaseDirectory}";
                var files    = Directory.GetFiles(basePath, "doc-api-*.xml");

                foreach (var file in files)
                {
                    swaggerDocConfig.IncludeXmlComments(file);
                }
            });

            var assembly = Assembly.GetExecutingAssembly();

            swaggerConfiguration.EnableSwaggerUi(c =>
            {
                c.CustomAsset("index", assembly, $"{EmbeddedResourceConstants.RESOURCE_ASSEMBLY_NAMESPACE}.index.html");
                c.InjectJavaScript(assembly, $"{EmbeddedResourceConstants.RESOURCE_ASSEMBLY_NAMESPACE}.swagger-ui-override.js");
                c.InjectStylesheet(assembly, $"{EmbeddedResourceConstants.RESOURCE_ASSEMBLY_NAMESPACE}.swagger-ui-override.css");
                c.EnableDiscoveryUrlSelector();
                c.DisableValidator();
            });

            ExtractTextResource(assembly, EmbeddedResourceConstants.RESOURCE_ASSEMBLY_NAMESPACE, KIT_SWAGGER_CONFIGURATION, KIT_SWAGGER_CONFIGURATION);
            ExtractTextResource(assembly, EmbeddedResourceConstants.RESOURCE_ASSEMBLY_NAMESPACE, KIT_DOCUMENTATION, KIT_DOCUMENTATION);
            ExtractTextResource(assembly, EmbeddedResourceConstants.RESOURCE_ASSEMBLY_NAMESPACE, KIT_INDEX, "swagger.html");
        }
Example #9
0
        /// <summary>
        /// 设置
        /// </summary>
        public static void Register(HttpConfiguration config, VersionedApiExplorer apiExplorer)
        {
            var thisAssembly = typeof(SwaggerConfig).Assembly;

            config.EnableSwagger(c =>
            {
                // By default, the service root url is inferred from the request used to access the docs.
                // However, there may be situations (e.g. proxy and load-balanced environments) where this does not
                // resolve correctly. You can workaround this by providing your own code to determine the root URL.
                //
                //c.RootUrl(req => GetRootUrlFromAppConfig());

                // If schemes are not explicitly provided in a Swagger 2.0 document, then the scheme used to access
                // the docs is taken as the default. If your API supports multiple schemes and you want to be explicit
                // about them, you can use the "Schemes" option as shown below.
                //
                //c.Schemes(new[] { "http", "https" });

                // Use "SingleApiVersion" to describe a single version API. Swagger 2.0 includes an "Info" object to
                // hold additional metadata for an API. Version and title are required but you can also provide
                // additional fields by chaining methods off SingleApiVersion.
                //
                //c.SingleApiVersion("v5", "DotneterWhj.WebApi");
                //c.SingleApiVersion("v6", "DotneterWhj.WebApi");

                // If you want the output Swagger docs to be indented properly, enable the "PrettyPrint" option.
                //
                //c.PrettyPrint();

                // If your API has multiple versions, use "MultipleApiVersions" instead of "SingleApiVersion".
                // In this case, you must provide a lambda that tells Swashbuckle which actions should be
                // included in the docs for a given API version. Like "SingleApiVersion", each call to "Version"
                // returns an "Info" builder so you can provide additional metadata per API version.
                //
                //c.MultipleApiVersions(
                //    (apiDesc, targetApiVersion) => ResolveVersionSupportByRouteConstraint(apiDesc, targetApiVersion),
                //    (vc) =>
                //    {
                //        vc.Version("v2", "Swashbuckle Dummy API V2");
                //        vc.Version("v1", "Swashbuckle Dummy API V1");
                //    });

                c.MultipleApiVersions(
                    (apiDescription, version) => apiDescription.GetGroupName() == version,
                    info =>
                {
                    foreach (var group in apiExplorer.ApiDescriptions)
                    {
                        //如果出现中文乱码问题,可以用vs新建一个SwaggerConfig,把原来SwaggerConfig中的内容拷过去,再删除自动创建的SwaggerConfig文件,
                        var description = "";

                        // 版本中所有的控制设置为Deprecated group.IsDeprecated 才会是true
                        if (group.IsDeprecated)
                        {
                            description += " 弃用的版本";
                        }

                        info.Version(group.Name, $"API {group.ApiVersion} {description}");
                    }
                });

                // You can use "BasicAuth", "ApiKey" or "OAuth2" options to describe security schemes for the API.
                // See https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md for more details.
                // NOTE: These only define the schemes and need to be coupled with a corresponding "security" property
                // at the document or operation level to indicate which schemes are required for an operation. To do this,
                // you'll need to implement a custom IDocumentFilter and/or IOperationFilter to set these properties
                // according to your specific authorization implementation
                //
                //c.BasicAuth("basic")
                //    .Description("Basic HTTP Authentication");
                //
                // NOTE: You must also configure 'EnableApiKeySupport' below in the SwaggerUI section
                //c.ApiKey("apiKey")
                //    .Description("API Key Authentication")
                //    .Name("apiKey")
                //    .In("header");
                //
                //c.OAuth2("oauth2")
                //    .Description("OAuth2 Implicit Grant")
                //    .Flow("implicit")
                //    .AuthorizationUrl("http://petstore.swagger.wordnik.com/api/oauth/dialog")
                //    //.TokenUrl("https://tempuri.org/token")
                //    .Scopes(scopes =>
                //    {
                //        scopes.Add("read", "Read access to protected resources");
                //        scopes.Add("write", "Write access to protected resources");
                //    });

                // Set this flag to omit descriptions for any actions decorated with the Obsolete attribute
                //c.IgnoreObsoleteActions();

                // Each operation be assigned one or more tags which are then used by consumers for various reasons.
                // For example, the swagger-ui groups operations according to the first tag of each operation.
                // By default, this will be controller name but you can use the "GroupActionsBy" option to
                // override with any value.
                //
                //c.GroupActionsBy(apiDesc => apiDesc.HttpMethod.ToString());

                // You can also specify a custom sort order for groups (as defined by "GroupActionsBy") to dictate
                // the order in which operations are listed. For example, if the default grouping is in place
                // (controller name) and you specify a descending alphabetic sort order, then actions from a
                // ProductsController will be listed before those from a CustomersController. This is typically
                // used to customize the order of groupings in the swagger-ui.
                //
                //c.OrderActionGroupsBy(new DescendingAlphabeticComparer());

                // If you annotate Controllers and API Types with
                // Xml comments (http://msdn.microsoft.com/en-us/library/b2s063f7(v=vs.110).aspx), you can incorporate
                // those comments into the generated docs and UI. You can enable this by providing the path to one or
                // more Xml comment files.
                //

                foreach (var xmlPath in GetXmlCommentsPath())
                {
                    c.IncludeXmlComments(xmlPath);
                }

                // Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types
                // exposed in your API. However, there may be occasions when more control of the output is needed.
                // This is supported through the "MapType" and "SchemaFilter" options:
                //
                // Use the "MapType" option to override the Schema generation for a specific type.
                // It should be noted that the resulting Schema will be placed "inline" for any applicable Operations.
                // While Swagger 2.0 supports inline definitions for "all" Schema types, the swagger-ui tool does not.
                // It expects "complex" Schemas to be defined separately and referenced. For this reason, you should only
                // use the "MapType" option when the resulting Schema is a primitive or array type. If you need to alter a
                // complex Schema, use a Schema filter.
                //
                //c.MapType<ProductType>(() => new Schema { type = "integer", format = "int32" });

                // If you want to post-modify "complex" Schemas once they've been generated, across the board or for a
                // specific type, you can wire up one or more Schema filters.
                //
                //c.SchemaFilter<ApplySchemaVendorExtensions>();

                // In a Swagger 2.0 document, complex types are typically declared globally and referenced by unique
                // Schema Id. By default, Swashbuckle does NOT use the full type name in Schema Ids. In most cases, this
                // works well because it prevents the "implementation detail" of type namespaces from leaking into your
                // Swagger docs and UI. However, if you have multiple types in your API with the same class name, you'll
                // need to opt out of this behavior to avoid Schema Id conflicts.
                //
                //c.UseFullTypeNameInSchemaIds();

                // Alternatively, you can provide your own custom strategy for inferring SchemaId's for
                // describing "complex" types in your API.
                //
                //c.SchemaId(t => t.FullName.Contains('`') ? t.FullName.Substring(0, t.FullName.IndexOf('`')) : t.FullName);

                // Set this flag to omit schema property descriptions for any type properties decorated with the
                // Obsolete attribute
                //c.IgnoreObsoleteProperties();

                // In accordance with the built in JsonSerializer, Swashbuckle will, by default, describe enums as integers.
                // You can change the serializer behavior by configuring the StringToEnumConverter globally or for a given
                // enum type. Swashbuckle will honor this change out-of-the-box. However, if you use a different
                // approach to serialize enums as strings, you can also force Swashbuckle to describe them as strings.
                //
                //c.DescribeAllEnumsAsStrings();

                // Similar to Schema filters, Swashbuckle also supports Operation and Document filters:
                //
                // Post-modify Operation descriptions once they've been generated by wiring up one or more
                // Operation filters.
                //
                //c.OperationFilter<AddDefaultResponse>();
                c.OperationFilter <HttpMethodHeaderFilter>();

                //
                // If you've defined an OAuth2 flow as described above, you could use a custom filter
                // to inspect some attribute on each action and infer which (if any) OAuth2 scopes are required
                // to execute the operation
                //
                //c.OperationFilter<AssignOAuth2SecurityRequirements>();

                // Post-modify the entire Swagger document by wiring up one or more Document filters.
                // This gives full control to modify the final SwaggerDocument. You should have a good understanding of
                // the Swagger 2.0 spec. - https://github.com/swagger-api/swagger-spec/blob/master/versions/2.0.md
                // before using this option.
                //
                //c.DocumentFilter<ApplyDocumentVendorExtensions>();
                // Swagger文档上对外不可见特性
                c.DocumentFilter <HiddenApiFilter>();
                c.DocumentFilter <EnumDocumentFilter>();

                // In contrast to WebApi, Swagger 2.0 does not include the query string component when mapping a URL
                // to an action. As a result, Swashbuckle will raise an exception if it encounters multiple actions
                // with the same path (sans query string) and HTTP method. You can workaround this by providing a
                // custom strategy to pick a winner or merge the descriptions for the purposes of the Swagger docs
                //
                c.ResolveConflictingActions(apiDescriptions => apiDescriptions.First());

                // Wrap the default SwaggerGenerator with additional behavior (e.g. caching) or provide an
                // alternative implementation for ISwaggerProvider with the CustomProvider option.
                //
                c.CustomProvider(defaultProvider => new SwaggerControllerDescProvider(defaultProvider, GetXmlCommentsPath()[0]));
            })
            .EnableSwaggerUi(c =>
            {
                // Use the "DocumentTitle" option to change the Document title.
                // Very helpful when you have multiple Swagger pages open, to tell them apart.
                //
                c.DocumentTitle("My Swagger UI");

                // Use the "InjectStylesheet" option to enrich the UI with one or more additional CSS stylesheets.
                // The file must be included in your project as an "Embedded Resource", and then the resource's
                // "Logical Name" is passed to the method as shown below.
                //
                //c.InjectStylesheet(containingAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testStyles1.css");

                // Use the "InjectJavaScript" option to invoke one or more custom JavaScripts after the swagger-ui
                // has loaded. The file must be included in your project as an "Embedded Resource", and then the resource's
                // "Logical Name" is passed to the method as shown above.
                //
                c.InjectJavaScript(System.Reflection.Assembly.GetAssembly(typeof(SwaggerControllerDescProvider)), "DotneterWhj.WebApi.Filters.Swagger.SwaggerWebApi.js");

                // The swagger-ui renders boolean data types as a dropdown. By default, it provides "true" and "false"
                // strings as the possible choices. You can use this option to change these to something else,
                // for example 0 and 1.
                //
                //c.BooleanValues(new[] { "0", "1" });

                // By default, swagger-ui will validate specs against swagger.io's online validator and display the result
                // in a badge at the bottom of the page. Use these options to set a different validator URL or to disable the
                // feature entirely.
                //c.SetValidatorUrl("http://localhost/validator");
                //c.DisableValidator();

                // Use this option to control how the Operation listing is displayed.
                // It can be set to "None" (default), "List" (shows operations for each resource),
                // or "Full" (fully expanded: shows operations and their details).
                //
                //c.DocExpansion(DocExpansion.List);

                // Specify which HTTP operations will have the 'Try it out!' option. An empty paramter list disables
                // it for all operations.
                //
                //c.SupportedSubmitMethods("GET", "HEAD");

                // Use the CustomAsset option to provide your own version of assets used in the swagger-ui.
                // It's typically used to instruct Swashbuckle to return your version instead of the default
                // when a request is made for "index.html". As with all custom content, the file must be included
                // in your project as an "Embedded Resource", and then the resource's "Logical Name" is passed to
                // the method as shown below.
                //
                //c.CustomAsset("index", containingAssembly, "YourWebApiProject.SwaggerExtensions.index.html");

                // If your API has multiple versions and you've applied the MultipleApiVersions setting
                // as described above, you can also enable a select box in the swagger-ui, that displays
                // a discovery URL for each version. This provides a convenient way for users to browse documentation
                // for different API versions.
                //
                c.EnableDiscoveryUrlSelector();

                // If your API supports the OAuth2 Implicit flow, and you've described it correctly, according to
                // the Swagger 2.0 specification, you can enable UI support as shown below.
                //
                //c.EnableOAuth2Support(
                //    clientId: "test-client-id",
                //    clientSecret: null,
                //    realm: "test-realm",
                //    appName: "Swagger UI"
                //    //additionalQueryStringParams: new Dictionary<string, string>() { { "foo", "bar" } }
                //);

                // If your API supports ApiKey, you can override the default values.
                // "apiKeyIn" can either be "query" or "header"
                //
                //c.EnableApiKeySupport("api-version", "header");
                c.EnableApiKeySupport("Authorization", "header");
            });
        }
Example #10
0
 public static SwaggerDocsConfig VersioningSwaggerDoc(this SwaggerDocsConfig config,
                                                      VersionedApiExplorer apiExplorer)
 {
     return(VersioningSwaggerDoc(config, apiExplorer, "API {0}"));
 }
Example #11
0
 public static SwaggerDocsConfig VersioningSwaggerDoc(this SwaggerDocsConfig config,
                                                      VersionedApiExplorer apiExplorer, string docTitleFormat)
 {
     return(VersioningSwaggerDoc(config, apiExplorer, docTitleFormat, "api-version"));
 }