diff --git a/Swagger/App_Start/SwaggerConfig.cs b/Swagger/App_Start/SwaggerConfig.cs index 2430ba8..cd22195 100644 --- a/Swagger/App_Start/SwaggerConfig.cs +++ b/Swagger/App_Start/SwaggerConfig.cs @@ -1,7 +1,14 @@ +using System; +using System.Linq; +using System.Web; using System.Web.Http; -using WebActivatorEx; +using System.Web.Http.Description; +using System.Web.Http.Routing.Constraints; +using System.Collections.Generic; + using Swagger; -using Swashbuckle.Application; +using Swagger.Net.Application; +using Swagger.Net; [assembly: PreApplicationStartMethod(typeof(SwaggerConfig), "Register")] @@ -34,12 +41,16 @@ public static void Register() // c.SingleApiVersion("v1", "Swagger"); + // Taking to long to load the swagger docs? Enable this option to start caching it + // + //c.AllowCachingSwaggerDoc(); + // 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 + // In this case, you must provide a lambda that tells Swagger-Net 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. // @@ -47,8 +58,8 @@ public static void Register() // (apiDesc, targetApiVersion) => ResolveVersionSupportByRouteConstraint(apiDesc, targetApiVersion), // (vc) => // { - // vc.Version("v2", "Swashbuckle Dummy API V2"); - // vc.Version("v1", "Swashbuckle Dummy API V1"); + // vc.Version("v2", "Swagger-Net Dummy API V2"); + // vc.Version("v1", "Swagger-Net Dummy API V1"); // }); // You can use "BasicAuth", "ApiKey" or "OAuth2" options to describe security schemes for the API. @@ -58,14 +69,9 @@ public static void Register() // 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"); + //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.ApiKey("apiKey", "header", "API Key Authentication"); // //c.OAuth2("oauth2") // .Description("OAuth2 Implicit Grant") @@ -81,6 +87,9 @@ public static void Register() // Set this flag to omit descriptions for any actions decorated with the Obsolete attribute //c.IgnoreObsoleteActions(); + // Comment this setting to disable Access-Control-Allow-Origin + c.AccessControlAllowOrigin("*"); + // 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 @@ -96,14 +105,17 @@ public static void Register() // //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 + // If you annotate Controllers and API Types with Xml comments: + // http://msdn.microsoft.com/en-us/library/b2s063f7(v=vs.110).aspx + // those comments will be incorporated into the generated docs and UI. + // Just make sure your comment file(s) have extension .XML + // You can add individual files by providing the path to one or // more Xml comment files. // - //c.IncludeXmlComments(GetXmlCommentsPath()); + //c.IncludeXmlComments(AppDomain.CurrentDomain.BaseDirectory + "file.ext"); + //c.IncludeAllXmlComments(thisAssembly, AppDomain.CurrentDomain.BaseDirectory); - // Swashbuckle makes a best attempt at generating Swagger compliant JSON schemas for the various types + // Swagger-Net 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: // @@ -122,7 +134,7 @@ public static void Register() //c.SchemaFilter(); // 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 + // Schema Id. By default, Swagger-Net 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. @@ -138,14 +150,14 @@ public static void Register() // Obsolete attribute //c.IgnoreObsoleteProperties(); - // In accordance with the built in JsonSerializer, Swashbuckle will, by default, describe enums as integers. + // In accordance with the built in JsonSerializer, if disabled Swagger-Net will 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. + // enum type. Swagger-Net will honor this change out-of-the-box. However, if you use a different + // approach to serialize enums as strings, you can also force Swagger-Net to describe them as strings. // - //c.DescribeAllEnumsAsStrings(); + c.DescribeAllEnumsAsStrings(camelCase: false); - // Similar to Schema filters, Swashbuckle also supports Operation and Document filters: + // Similar to Schema filters, Swagger-Net also supports Operation and Document filters: // // Post-modify Operation descriptions once they've been generated by wiring up one or more // Operation filters. @@ -166,7 +178,7 @@ public static void Register() //c.DocumentFilter(); // 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 + // to an action. As a result, Swagger-Net 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 // @@ -188,13 +200,13 @@ public static void Register() // 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"); + //c.InjectStylesheet(thisAssembly, "Swagger.Net.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(thisAssembly, "Swashbuckle.Dummy.SwaggerExtensions.testScript1.js"); + //c.InjectJavaScript(thisAssembly, "Swagger.Net.Dummy.SwaggerExtensions.testScript1.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, @@ -205,27 +217,45 @@ public static void Register() // 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.SetValidatorUrl("https://online.swagger.io/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); + c.DocExpansion(DocExpansion.Full); + + // Controls how models are shown when the API is first rendered. (The user can always switch + // the rendering for a given model by clicking the 'Model' and 'Example Value' links.) It can be + // set to 'model' or 'example', and the default is 'example'. + // + //c.DefaultModelRendering(DefaultModelRender.Model); + + // Use this option to control the expansion depth for models. + // + //c.DefaultModelExpandDepth(0); - // Specify which HTTP operations will have the 'Try it out!' option. An empty paramter list disables + // Limit the number of operations shown to a smaller value + // + c.UImaxDisplayedTags(100); + + // Filter the operations works as a search, to disable set to "null" + // + c.UIfilter("''"); + + // Specify which HTTP operations will have the 'Try it out!' option. An empty parameter 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 + // It's typically used to instruct Swagger-Net 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"); + //c.CustomAsset("index", thisAssembly, "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 @@ -244,12 +274,72 @@ public static void Register() // appName: "Swagger UI" // //additionalQueryStringParams: new Dictionary() { { "foo", "bar" } } //); - - // If your API supports ApiKey, you can override the default values. - // "apiKeyIn" can either be "query" or "header" - // - //c.EnableApiKeySupport("apiKey", "header"); }); } + + public static bool ResolveVersionSupportByRouteConstraint(ApiDescription apiDesc, string targetApiVersion) + { + return (apiDesc.Route.RouteTemplate.ToLower().Contains(targetApiVersion.ToLower())); + } + + private class ApplyDocumentVendorExtensions : IDocumentFilter + { + public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer) + { + // Include the given data type in the final SwaggerDocument + // + //schemaRegistry.GetOrRegister(typeof(ExtraType)); + } + } + + public class AssignOAuth2SecurityRequirements : IOperationFilter + { + public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) + { + // Correspond each "Authorize" role to an oauth2 scope + var scopes = apiDescription.ActionDescriptor.GetFilterPipeline() + .Select(filterInfo => filterInfo.Instance) + .OfType() + .SelectMany(attr => attr.Roles.Split(',')) + .Distinct(); + + if (scopes.Any()) + { + if (operation.security == null) + operation.security = new List>>(); + + var oAuthRequirements = new Dictionary> + { + { "oauth2", scopes } + }; + + operation.security.Add(oAuthRequirements); + } + } + } + + private class ApplySchemaVendorExtensions : ISchemaFilter + { + public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type) + { + // Modify the example values in the final SwaggerDocument + // + if (schema.properties != null) + { + foreach (var p in schema.properties) + { + switch (p.Value.format) + { + case "int32": + p.Value.example = 123; + break; + case "double": + p.Value.example = 9858.216; + break; + } + } + } + } + } } } diff --git a/Swagger/App_Start/WebApiConfig.cs b/Swagger/App_Start/WebApiConfig.cs index 1a495df..800dbbf 100644 --- a/Swagger/App_Start/WebApiConfig.cs +++ b/Swagger/App_Start/WebApiConfig.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Web.Http; +using System.Web.Http.Cors; namespace Swagger { @@ -10,7 +11,7 @@ public static class WebApiConfig public static void Register(HttpConfiguration config) { // Web API configuration and services - + config.EnableCors(new EnableCorsAttribute("*", "*", "*")); // Web API routes config.MapHttpAttributeRoutes(); diff --git a/Swagger/Controllers/ValuesController.cs b/Swagger/Controllers/ValuesController.cs index fbb8886..32248b0 100644 --- a/Swagger/Controllers/ValuesController.cs +++ b/Swagger/Controllers/ValuesController.cs @@ -1,55 +1,21 @@ -using Swashbuckle.Swagger; -using Swashbuckle.Swagger.Annotations; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Net; -using System.Net.Http; +using Swagger.Models; using System.Web.Http; namespace Swagger.Controllers { - [RoutePrefix("Values")] + [RoutePrefix("SchemaFilter")] public class ValuesController : ApiController { - [HttpGet] - [Route("Working")] - [SwaggerResponse(HttpStatusCode.OK, "OK", typeof(WorkingGetResponse))] - public IHttpActionResult Working() + [Route("Regular")] + public SchemaFilterGetResponse GetSchemaFilter() { - return Ok(new WorkingGetResponse { Strings = new List { "value1", "value2" } }); + return null; } - [HttpGet] - [Route("NotWorking")] - [SwaggerResponse(HttpStatusCode.OK, "OK", typeof(NotWorkingGetResponse))] - public IHttpActionResult NotWorking() + [Route("Inherited")] + public InheritedGetResponse GetInheritedSchemaFilter() { - return Ok(new NotWorkingGetResponse { Strings = new List { "value1", "value2" } }); - } - } - - internal class NotWorkingGetResponse : BaseGetResponse - { - public IEnumerable Strings { get; set; } = new List(); - } - - [SwaggerSchemaFilter(typeof(SingleJsonArraySchemaFilter))] - internal class WorkingGetResponse : BaseGetResponse - { - public IEnumerable Strings { get; set; } = new List(); - } - - [SwaggerSchemaFilter(typeof(SingleJsonArraySchemaFilter))] - internal abstract class BaseGetResponse - { - } - - internal class SingleJsonArraySchemaFilter : ISchemaFilter - { - public void Apply(Schema schema, SchemaRegistry schemaRegistry, Type type) - { - schema.@default = new { working = true }; + return null; } } } diff --git a/Swagger/Models/GetResponse.cs b/Swagger/Models/GetResponse.cs new file mode 100644 index 0000000..d2d2ca5 --- /dev/null +++ b/Swagger/Models/GetResponse.cs @@ -0,0 +1,29 @@ +using Swagger.Net; +using Swagger.Net.Annotations; +using System; +using System.Collections.Generic; + +namespace Swagger.Models +{ + [SwaggerSchemaFilter(typeof(AddDefault))] + public class SchemaFilterGetResponse + { + public IEnumerable Strings { get; set; } = new List(); + } + + public class InheritedGetResponse : Base + { + public IEnumerable Strings { get; set; } = new List(); + } + + [SwaggerSchemaFilter(typeof(AddDefault))] + public abstract class Base { } + + public class AddDefault : ISchemaFilter + { + public void Apply(Schema schema, SchemaRegistry sr, Type t) + { + schema.example = schema.@default = new { working = true }; + } + } +} \ No newline at end of file diff --git a/Swagger/Swagger.csproj b/Swagger/Swagger.csproj index 80fff98..9c56957 100644 --- a/Swagger/Swagger.csproj +++ b/Swagger/Swagger.csproj @@ -50,20 +50,26 @@ ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.7\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - - ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll - - ..\packages\Swashbuckle.Core.5.6.0\lib\net40\Swashbuckle.Core.dll + + ..\packages\Swagger-Net.8.3.5.2\lib\net45\Swagger.Net.dll + + ..\packages\Microsoft.AspNet.Cors.5.2.3\lib\net45\System.Web.Cors.dll + + + ..\packages\Microsoft.AspNet.WebApi.Cors.5.2.3\lib\net45\System.Web.Http.Cors.dll + @@ -160,6 +166,7 @@ Global.asax + @@ -190,7 +197,6 @@ - diff --git a/Swagger/Web.config b/Swagger/Web.config index 6730c11..c991834 100644 --- a/Swagger/Web.config +++ b/Swagger/Web.config @@ -34,7 +34,7 @@ - + diff --git a/Swagger/packages.config b/Swagger/packages.config index 20c936f..c7fca9d 100644 --- a/Swagger/packages.config +++ b/Swagger/packages.config @@ -10,12 +10,14 @@ + + @@ -23,10 +25,9 @@ - + - - + \ No newline at end of file