forked from loafle/openapi-generator-original
Added Base Path support as well as PathParameterValidation (#7120)
* Ran bin/aspnetcore-petstore-server.sh * Added BasePath filter and Validation filter * Updated filters and added Attribute generators * Removed newline * Updated samples
This commit is contained in:
parent
3c8293bbcf
commit
d881cb39bf
@ -120,6 +120,9 @@ public class AspNetCoreServerCodegen extends AbstractCSharpCodegen {
|
||||
|
||||
supportingFiles.add(new SupportingFile("Properties" + File.separator + "launchSettings.json", packageFolder + File.separator + "Properties", "launchSettings.json"));
|
||||
|
||||
supportingFiles.add(new SupportingFile("Filters" + File.separator + "BasePathDocumentFilter.mustache", packageFolder + File.separator + "Filters", "BasePathDocumentFilter.cs"));
|
||||
supportingFiles.add(new SupportingFile("Filters" + File.separator + "PathParameterValidationFilter.mustache", packageFolder + File.separator + "Filters", "PathParameterValidationFilter.cs"));
|
||||
|
||||
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "README.md", packageFolder + File.separator + "wwwroot", "README.md"));
|
||||
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "index.html", packageFolder + File.separator + "wwwroot", "index.html"));
|
||||
supportingFiles.add(new SupportingFile("wwwroot" + File.separator + "web.config", packageFolder + File.separator + "wwwroot", "web.config"));
|
||||
|
@ -0,0 +1,50 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace {{packageName}}.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// BasePath Document Filter sets BasePath property of Swagger and removes it from the individual URL paths
|
||||
/// </summary>
|
||||
public class BasePathDocumentFilter : IDocumentFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="basePath">BasePath to remove from Operations</param>
|
||||
public BasePathDocumentFilter(string basePath)
|
||||
{
|
||||
BasePath = basePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the BasePath of the Swagger Doc
|
||||
/// </summary>
|
||||
/// <returns>The BasePath of the Swagger Doc</returns>
|
||||
public string BasePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Apply the filter
|
||||
/// </summary>
|
||||
/// <param name="swaggerDoc">SwaggerDocument</param>
|
||||
/// <param name="context">FilterContext</param>
|
||||
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
swaggerDoc.BasePath = this.BasePath;
|
||||
|
||||
var pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(this.BasePath)).ToList();
|
||||
|
||||
foreach (var path in pathsToModify)
|
||||
{
|
||||
if (path.Key.StartsWith(this.BasePath))
|
||||
{
|
||||
string newKey = Regex.Replace(path.Key, $"^{this.BasePath}", string.Empty);
|
||||
swaggerDoc.Paths.Remove(path.Key);
|
||||
swaggerDoc.Paths.Add(newKey, path.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace {{packageName}}.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// Path Parameter Validation Filter
|
||||
/// </summary>
|
||||
public class PathParameterValidationFilter : IOperationFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="operation">Operation</param>
|
||||
/// <param name="context">OperationFilterContext</param>
|
||||
public void Apply(Operation operation, OperationFilterContext context)
|
||||
{
|
||||
var pars = context.ApiDescription.ParameterDescriptions;
|
||||
|
||||
foreach (var par in pars)
|
||||
{
|
||||
var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);
|
||||
|
||||
var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes;
|
||||
|
||||
if (attributes != null && attributes.Count() > 0 && swaggerParam != null)
|
||||
{
|
||||
// Required - [Required]
|
||||
var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
|
||||
if (requiredAttr != null)
|
||||
{
|
||||
swaggerParam.Required = true;
|
||||
}
|
||||
|
||||
// Regex Pattern [RegularExpression]
|
||||
var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute));
|
||||
if (regexAttr != null)
|
||||
{
|
||||
string regex = (string)regexAttr.ConstructorArguments[0].Value;
|
||||
if (swaggerParam is NonBodyParameter)
|
||||
{
|
||||
((NonBodyParameter)swaggerParam).Pattern = regex;
|
||||
}
|
||||
}
|
||||
|
||||
// String Length [StringLength]
|
||||
int? minLenght = null, maxLength = null;
|
||||
var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
|
||||
if (stringLengthAttr != null)
|
||||
{
|
||||
if (stringLengthAttr.NamedArguments.Count == 1)
|
||||
{
|
||||
minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
|
||||
}
|
||||
maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value;
|
||||
}
|
||||
|
||||
var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
|
||||
if (minLengthAttr != null)
|
||||
{
|
||||
minLenght = (int)minLengthAttr.ConstructorArguments[0].Value;
|
||||
}
|
||||
|
||||
var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
|
||||
if (maxLengthAttr != null)
|
||||
{
|
||||
maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value;
|
||||
}
|
||||
|
||||
if (swaggerParam is NonBodyParameter)
|
||||
{
|
||||
((NonBodyParameter)swaggerParam).MinLength = minLenght;
|
||||
((NonBodyParameter)swaggerParam).MaxLength = maxLength;
|
||||
}
|
||||
|
||||
// Range [Range]
|
||||
var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
|
||||
if (rangeAttr != null)
|
||||
{
|
||||
int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value;
|
||||
int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value;
|
||||
|
||||
if (swaggerParam is NonBodyParameter)
|
||||
{
|
||||
((NonBodyParameter)swaggerParam).Minimum = rangeMin;
|
||||
((NonBodyParameter)swaggerParam).Maximum = rangeMax;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using {{packageName}}.Filters;
|
||||
|
||||
namespace {{packageName}}
|
||||
{
|
||||
@ -62,6 +63,12 @@ namespace {{packageName}}
|
||||
c.CustomSchemaIds(type => type.FriendlyId(true));
|
||||
c.DescribeAllEnumsAsStrings();
|
||||
c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml");
|
||||
{{#basePathWithoutHost}}
|
||||
// Sets the basePath property in the Swagger document generated
|
||||
c.DocumentFilter<BasePathDocumentFilter>("{{{basePathWithoutHost}}}");
|
||||
{{/basePathWithoutHost}}
|
||||
// Do validation of path parameters w. DataAnnotation attributes
|
||||
c.OperationFilter<PathParameterValidationFilter>();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using {{packageName}}.Attributes;
|
||||
using {{packageName}}.Models;
|
||||
|
||||
|
@ -1 +1 @@
|
||||
{{#isFormParam}}[FromForm]{{&dataType}} {{paramName}}{{/isFormParam}}
|
||||
{{#isFormParam}}[FromForm]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isFormParam}}
|
@ -1 +1 @@
|
||||
{{#isHeaderParam}}[FromHeader]{{&dataType}} {{paramName}}{{/isHeaderParam}}
|
||||
{{#isHeaderParam}}[FromHeader]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isHeaderParam}}
|
@ -1 +1 @@
|
||||
{{#isPathParam}}[FromRoute]{{&dataType}} {{paramName}}{{/isPathParam}}
|
||||
{{#isPathParam}}[FromRoute]{{#required}}[Required]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isPathParam}}
|
@ -1 +1 @@
|
||||
{{#isQueryParam}}[FromQuery]{{&dataType}} {{paramName}}{{/isQueryParam}}
|
||||
{{#isQueryParam}}[FromQuery]{{#required}}[Required()]{{/required}}{{#pattern}}[RegularExpression("{{{pattern}}}")]{{/pattern}}{{#minLength}}{{#maxLength}}[StringLength({{maxLength}}, MinimumLength={{minLength}}){{/maxLength}}{{/minLength}}{{#minLength}}{{^maxLength}} [MinLength({{minLength}})]{{/maxLength}}{{/minLength}}{{^minLength}}{{#maxLength}} [MaxLength({{maxLength}})]{{/maxLength}}{{/minLength}}{{#minimum}}{{#maximum}}[Range({{minimum}}, {{maximum}})]{{/maximum}}{{/minimum}}{{&dataType}} {{paramName}}{{/isQueryParam}}
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using IO.Swagger.Attributes;
|
||||
using IO.Swagger.Models;
|
||||
|
||||
@ -60,7 +61,7 @@ namespace IO.Swagger.Controllers
|
||||
[Route("/v2/pet/{petId}")]
|
||||
[ValidateModelState]
|
||||
[SwaggerOperation("DeletePet")]
|
||||
public virtual IActionResult DeletePet([FromRoute]long? petId, [FromHeader]string apiKey)
|
||||
public virtual IActionResult DeletePet([FromRoute][Required]long? petId, [FromHeader]string apiKey)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(400);
|
||||
@ -82,7 +83,7 @@ namespace IO.Swagger.Controllers
|
||||
[SwaggerOperation("FindPetsByStatus")]
|
||||
[SwaggerResponse(200, typeof(List<Pet>), "successful operation")]
|
||||
[SwaggerResponse(400, typeof(List<Pet>), "Invalid status value")]
|
||||
public virtual IActionResult FindPetsByStatus([FromQuery]List<string> status)
|
||||
public virtual IActionResult FindPetsByStatus([FromQuery][Required()]List<string> status)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(List<Pet>));
|
||||
@ -112,7 +113,7 @@ namespace IO.Swagger.Controllers
|
||||
[SwaggerOperation("FindPetsByTags")]
|
||||
[SwaggerResponse(200, typeof(List<Pet>), "successful operation")]
|
||||
[SwaggerResponse(400, typeof(List<Pet>), "Invalid tag value")]
|
||||
public virtual IActionResult FindPetsByTags([FromQuery]List<string> tags)
|
||||
public virtual IActionResult FindPetsByTags([FromQuery][Required()]List<string> tags)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(List<Pet>));
|
||||
@ -144,7 +145,7 @@ namespace IO.Swagger.Controllers
|
||||
[SwaggerResponse(200, typeof(Pet), "successful operation")]
|
||||
[SwaggerResponse(400, typeof(Pet), "Invalid ID supplied")]
|
||||
[SwaggerResponse(404, typeof(Pet), "Pet not found")]
|
||||
public virtual IActionResult GetPetById([FromRoute]long? petId)
|
||||
public virtual IActionResult GetPetById([FromRoute][Required]long? petId)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(Pet));
|
||||
@ -203,7 +204,7 @@ namespace IO.Swagger.Controllers
|
||||
[Route("/v2/pet/{petId}")]
|
||||
[ValidateModelState]
|
||||
[SwaggerOperation("UpdatePetWithForm")]
|
||||
public virtual IActionResult UpdatePetWithForm([FromRoute]long? petId, [FromForm]string name, [FromForm]string status)
|
||||
public virtual IActionResult UpdatePetWithForm([FromRoute][Required]long? petId, [FromForm]string name, [FromForm]string status)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 405 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(405);
|
||||
@ -225,7 +226,7 @@ namespace IO.Swagger.Controllers
|
||||
[ValidateModelState]
|
||||
[SwaggerOperation("UploadFile")]
|
||||
[SwaggerResponse(200, typeof(ApiResponse), "successful operation")]
|
||||
public virtual IActionResult UploadFile([FromRoute]long? petId, [FromForm]string additionalMetadata, [FromForm]System.IO.Stream file)
|
||||
public virtual IActionResult UploadFile([FromRoute][Required]long? petId, [FromForm]string additionalMetadata, [FromForm]System.IO.Stream file)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(ApiResponse));
|
||||
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using IO.Swagger.Attributes;
|
||||
using IO.Swagger.Models;
|
||||
|
||||
@ -41,7 +42,7 @@ namespace IO.Swagger.Controllers
|
||||
[Route("/v2/store/order/{orderId}")]
|
||||
[ValidateModelState]
|
||||
[SwaggerOperation("DeleteOrder")]
|
||||
public virtual IActionResult DeleteOrder([FromRoute]string orderId)
|
||||
public virtual IActionResult DeleteOrder([FromRoute][Required]string orderId)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(400);
|
||||
@ -92,7 +93,7 @@ namespace IO.Swagger.Controllers
|
||||
[SwaggerResponse(200, typeof(Order), "successful operation")]
|
||||
[SwaggerResponse(400, typeof(Order), "Invalid ID supplied")]
|
||||
[SwaggerResponse(404, typeof(Order), "Order not found")]
|
||||
public virtual IActionResult GetOrderById([FromRoute]long? orderId)
|
||||
public virtual IActionResult GetOrderById([FromRoute][Required][Range(1, 5)]long? orderId)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(Order));
|
||||
|
@ -20,6 +20,7 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using IO.Swagger.Attributes;
|
||||
using IO.Swagger.Models;
|
||||
|
||||
@ -98,7 +99,7 @@ namespace IO.Swagger.Controllers
|
||||
[Route("/v2/user/{username}")]
|
||||
[ValidateModelState]
|
||||
[SwaggerOperation("DeleteUser")]
|
||||
public virtual IActionResult DeleteUser([FromRoute]string username)
|
||||
public virtual IActionResult DeleteUser([FromRoute][Required]string username)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(400);
|
||||
@ -125,7 +126,7 @@ namespace IO.Swagger.Controllers
|
||||
[SwaggerResponse(200, typeof(User), "successful operation")]
|
||||
[SwaggerResponse(400, typeof(User), "Invalid username supplied")]
|
||||
[SwaggerResponse(404, typeof(User), "User not found")]
|
||||
public virtual IActionResult GetUserByName([FromRoute]string username)
|
||||
public virtual IActionResult GetUserByName([FromRoute][Required]string username)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(User));
|
||||
@ -159,7 +160,7 @@ namespace IO.Swagger.Controllers
|
||||
[SwaggerOperation("LoginUser")]
|
||||
[SwaggerResponse(200, typeof(string), "successful operation")]
|
||||
[SwaggerResponse(400, typeof(string), "Invalid username/password supplied")]
|
||||
public virtual IActionResult LoginUser([FromQuery]string username, [FromQuery]string password)
|
||||
public virtual IActionResult LoginUser([FromQuery][Required()]string username, [FromQuery][Required()]string password)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 200 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(200, default(string));
|
||||
@ -206,7 +207,7 @@ namespace IO.Swagger.Controllers
|
||||
[Route("/v2/user/{username}")]
|
||||
[ValidateModelState]
|
||||
[SwaggerOperation("UpdateUser")]
|
||||
public virtual IActionResult UpdateUser([FromRoute]string username, [FromBody]User body)
|
||||
public virtual IActionResult UpdateUser([FromRoute][Required]string username, [FromBody]User body)
|
||||
{
|
||||
//TODO: Uncomment the next line to return response 400 or use other options such as return this.NotFound(), return this.BadRequest(..), ...
|
||||
// return StatusCode(400);
|
||||
|
@ -0,0 +1,50 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace IO.Swagger.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// BasePath Document Filter sets BasePath property of Swagger and removes it from the individual URL paths
|
||||
/// </summary>
|
||||
public class BasePathDocumentFilter : IDocumentFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="basePath">BasePath to remove from Operations</param>
|
||||
public BasePathDocumentFilter(string basePath)
|
||||
{
|
||||
BasePath = basePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the BasePath of the Swagger Doc
|
||||
/// </summary>
|
||||
/// <returns>The BasePath of the Swagger Doc</returns>
|
||||
public string BasePath { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Apply the filter
|
||||
/// </summary>
|
||||
/// <param name="swaggerDoc">SwaggerDocument</param>
|
||||
/// <param name="context">FilterContext</param>
|
||||
public void Apply(SwaggerDocument swaggerDoc, DocumentFilterContext context)
|
||||
{
|
||||
swaggerDoc.BasePath = this.BasePath;
|
||||
|
||||
var pathsToModify = swaggerDoc.Paths.Where(p => p.Key.StartsWith(this.BasePath)).ToList();
|
||||
|
||||
foreach (var path in pathsToModify)
|
||||
{
|
||||
if (path.Key.StartsWith(this.BasePath))
|
||||
{
|
||||
string newKey = Regex.Replace(path.Key, $"^{this.BasePath}", string.Empty);
|
||||
swaggerDoc.Paths.Remove(path.Key);
|
||||
swaggerDoc.Paths.Add(newKey, path.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.Controllers;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
|
||||
namespace IO.Swagger.Filters
|
||||
{
|
||||
/// <summary>
|
||||
/// Path Parameter Validation Filter
|
||||
/// </summary>
|
||||
public class PathParameterValidationFilter : IOperationFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="operation">Operation</param>
|
||||
/// <param name="context">OperationFilterContext</param>
|
||||
public void Apply(Operation operation, OperationFilterContext context)
|
||||
{
|
||||
var pars = context.ApiDescription.ParameterDescriptions;
|
||||
|
||||
foreach (var par in pars)
|
||||
{
|
||||
var swaggerParam = operation.Parameters.SingleOrDefault(p => p.Name == par.Name);
|
||||
|
||||
var attributes = ((ControllerParameterDescriptor)par.ParameterDescriptor).ParameterInfo.CustomAttributes;
|
||||
|
||||
if (attributes != null && attributes.Count() > 0 && swaggerParam != null)
|
||||
{
|
||||
// Required - [Required]
|
||||
var requiredAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RequiredAttribute));
|
||||
if (requiredAttr != null)
|
||||
{
|
||||
swaggerParam.Required = true;
|
||||
}
|
||||
|
||||
// Regex Pattern [RegularExpression]
|
||||
var regexAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RegularExpressionAttribute));
|
||||
if (regexAttr != null)
|
||||
{
|
||||
string regex = (string)regexAttr.ConstructorArguments[0].Value;
|
||||
if (swaggerParam is NonBodyParameter)
|
||||
{
|
||||
((NonBodyParameter)swaggerParam).Pattern = regex;
|
||||
}
|
||||
}
|
||||
|
||||
// String Length [StringLength]
|
||||
int? minLenght = null, maxLength = null;
|
||||
var stringLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(StringLengthAttribute));
|
||||
if (stringLengthAttr != null)
|
||||
{
|
||||
if (stringLengthAttr.NamedArguments.Count == 1)
|
||||
{
|
||||
minLenght = (int)stringLengthAttr.NamedArguments.Single(p => p.MemberName == "MinimumLength").TypedValue.Value;
|
||||
}
|
||||
maxLength = (int)stringLengthAttr.ConstructorArguments[0].Value;
|
||||
}
|
||||
|
||||
var minLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MinLengthAttribute));
|
||||
if (minLengthAttr != null)
|
||||
{
|
||||
minLenght = (int)minLengthAttr.ConstructorArguments[0].Value;
|
||||
}
|
||||
|
||||
var maxLengthAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(MaxLengthAttribute));
|
||||
if (maxLengthAttr != null)
|
||||
{
|
||||
maxLength = (int)maxLengthAttr.ConstructorArguments[0].Value;
|
||||
}
|
||||
|
||||
if (swaggerParam is NonBodyParameter)
|
||||
{
|
||||
((NonBodyParameter)swaggerParam).MinLength = minLenght;
|
||||
((NonBodyParameter)swaggerParam).MaxLength = maxLength;
|
||||
}
|
||||
|
||||
// Range [Range]
|
||||
var rangeAttr = attributes.FirstOrDefault(p => p.AttributeType == typeof(RangeAttribute));
|
||||
if (rangeAttr != null)
|
||||
{
|
||||
int rangeMin = (int)rangeAttr.ConstructorArguments[0].Value;
|
||||
int rangeMax = (int)rangeAttr.ConstructorArguments[1].Value;
|
||||
|
||||
if (swaggerParam is NonBodyParameter)
|
||||
{
|
||||
((NonBodyParameter)swaggerParam).Minimum = rangeMin;
|
||||
((NonBodyParameter)swaggerParam).Maximum = rangeMax;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ using Newtonsoft.Json.Converters;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
using Swashbuckle.AspNetCore.Swagger;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using IO.Swagger.Filters;
|
||||
|
||||
namespace IO.Swagger
|
||||
{
|
||||
@ -71,6 +72,10 @@ namespace IO.Swagger
|
||||
c.CustomSchemaIds(type => type.FriendlyId(true));
|
||||
c.DescribeAllEnumsAsStrings();
|
||||
c.IncludeXmlComments($"{AppContext.BaseDirectory}{Path.DirectorySeparatorChar}{_hostingEnv.ApplicationName}.xml");
|
||||
// Sets the basePath property in the Swagger document generated
|
||||
c.DocumentFilter<BasePathDocumentFilter>("/v2");
|
||||
// Do validation of path parameters w. DataAnnotation attributes
|
||||
c.OperationFilter<PathParameterValidationFilter>();
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user