添加项目文件。

This commit is contained in:
luoyunchong
2020-08-09 14:50:47 +08:00
parent 5d21b53ae2
commit 483c410943
51 changed files with 2367 additions and 0 deletions

20
test/Basic/Basic.csproj Normal file
View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp3.0</TargetFramework>
<NoWarn>$(NoWarn);1591</NoWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="5.5.1" />
</ItemGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\IGeekFan.AspNetCore.SwaggerUI\IGeekFan.AspNetCore.Knife4jUI.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,118 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
/// <summary>
/// Summary for CrudActionsController
/// </summary>
[Route("/products")]
[Produces("application/json")]
[ApiExplorerSettings(GroupName = "v1")]
public class CrudActionsController
{
/// <summary>
/// Creates a <paramref name="product"/>
/// </summary>
/// <remarks>
/// ## Heading 1
///
/// POST /products
/// {
/// "id": "123",
/// "description": "Some product"
/// }
///
/// </remarks>
/// <param name="product"></param>
/// <returns></returns>
[HttpPost(Name = "CreateProduct")]
public Product Create([FromBody, Required] Product product)
{
return product;
}
/// <summary>
/// Searches the collection of products by description key words
/// </summary>
/// <param name="keywords" example="hello">A list of search terms</param>
/// <returns></returns>
[HttpGet(Name = "SearchProducts")]
public IEnumerable<Product> Get([FromQuery(Name = "kw")] string keywords = "foobar")
{
return new[]
{
new Product { Id = 1, Description = "A product" },
new Product { Id = 2, Description = "Another product" },
};
}
/// <summary>
/// Returns a specific product
/// </summary>
/// <param name="id" example="111">The product id</param>
/// <returns></returns>
[HttpGet("{id}", Name = "GetProduct")]
public Product Get(int id)
{
return new Product { Id = id, Description = "A product" };
}
/// <summary>
/// Updates all properties of a specific product
/// </summary>
/// <param name="id" example="222"></param>
/// <param name="product"></param>
[HttpPut("{id}", Name = "UpdateProduct")]
public void Update(int id, [FromBody, Required] Product product)
{
}
/// <summary>
/// Updates some properties of a specific product
/// </summary>
/// <param name="id" example="333"></param>
/// <param name="updates"></param>
[HttpPatch("{id}", Name = "PatchProduct")]
public void Patch(int id, [FromBody, Required] IDictionary<string, object> updates)
{
}
/// <summary>
/// Deletes a specific product
/// </summary>
/// <param name="id" example="444"></param>
[HttpDelete("{id}", Name = "DeleteProduct")]
public void Delete(int id)
{
}
}
public enum ProductStatus
{
All = 0,
OutOfStock = 1,
InStock = 2
}
/// <summary>
/// Represents a product
/// </summary>
public class Product
{
/// <summary>
/// Uniquely identifies the product
/// </summary>
public int Id { get; set; }
/// <summary>
/// Describes the product
/// </summary>
public string Description { get; set; }
public ProductStatus Status { get; set; }
public ProductStatus? Status2 { get; set; }
}
}

View File

@ -0,0 +1,55 @@
using System;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Produces("application/json")]
public class DataAnnotationsController : Controller
{
[HttpPost("payments/authorize")]
[ProducesResponseType(200, Type = typeof(string))]
public IActionResult AuthorizePayment([FromBody, Required]PaymentRequest request)
{
if (!ModelState.IsValid)
return new BadRequestObjectResult(ModelState);
return new ObjectResult("123456");
}
[HttpPut("payments/{paymentId}/cancel")]
public IActionResult CancelPayment([MinLength(6)]string paymentId)
{
return Ok();
}
}
public class PaymentRequest
{
[Required]
public Transaction Transaction { get; set; }
[Required]
public CreditCard CreditCard { get; set; }
}
public class Transaction
{
[Required]
public decimal Amount { get; set; }
public string Note { get; set; }
}
public class CreditCard
{
[Required, RegularExpression("^[3-6]?\\d{12,15}$")]
public string CardNumber { get; set; }
[Required, Range(1, 12)]
public int ExpMonth { get; set; }
[Required, Range(14, 99)]
public int ExpYear { get; set; }
}
}

View File

@ -0,0 +1,8 @@
using System;
namespace Basic.Controllers
{
internal class DefaultValuesAttribute : Attribute
{
}
}

View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Dynamic;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Produces("application/json")]
public class DynamicTypesController
{
[HttpPost("kittens")]
public int CreateKitten([FromBody]dynamic kitten)
{
return 1;
}
[HttpGet("unicorns")]
public ExpandoObject GetUnicorns()
{
return new ExpandoObject();
}
[HttpPost("dragons")]
public IActionResult CreateDragons([FromBody]object dragon)
{
return new ObjectResult(1);
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Route("files")]
public class FilesController : Controller
{
[HttpPost("single")]
public IActionResult PostFile(IFormFile file)
{
throw new NotImplementedException();
}
[HttpPost("multiple")]
public IActionResult PostFiles(IFormFileCollection files)
{
throw new NotImplementedException();
}
[HttpPost("form-with-file")]
public IActionResult PostFormWithFile([FromForm]FormWithFile formWithFile)
{
throw new NotImplementedException();
}
[HttpGet("{name}")]
[Produces("application/octet-stream", Type = typeof(FileResult))]
public FileResult GetFile(string name)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.WriteLine("Hello world!");
writer.Flush();
stream.Position = 0;
return File(stream, "application/octet-stream", name);
}
}
public class FormWithFile
{
public string Name { get; set; }
public IFormFile File { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace Basic.Controllers
{
public class FromFormParamsController
{
[HttpPost("registrations")]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult PostForm([FromForm]RegistrationForm form)
{
throw new System.NotImplementedException();
}
}
public class RegistrationForm
{
public string Name { get; set; }
public IEnumerable<int> PhoneNumbers { get; set; }
}
}

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
namespace Basic.Controllers
{
[Produces("application/json")]
public class FromQueryParamsController
{
[HttpGet("addresses/validate")]
public IActionResult ValidateAddress([FromQuery]Address address)
{
return new NoContentResult();
}
[HttpGet("zip-codes/validate")]
public IActionResult ValidateZipCodes([FromQuery]IEnumerable<string> zipCodes)
{
return new NoContentResult();
}
}
public class Address
{
/// <summary>
/// 3-letter ISO country code
/// </summary>
[Required]
public string Country { get; set; }
/// <summary>
/// Name of city
/// </summary>
[DefaultValue("Seattle")]
public string City { get; set; }
}
}

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Produces("application/json")]
public class JsonAnnotationsController
{
[HttpGet("/promotions")]
public IEnumerable<Promotion> GetPromotions()
{
return new[]
{
new Promotion { Code = "A", DiscountType = DiscountType.Amount, Discount = 30 },
new Promotion { Code = "B", DiscountType = DiscountType.Percentage, Discount = 10 }
};
}
}
public class Promotion
{
[JsonPropertyName("promo-code")]
public string Code { get; set; }
public DiscountType DiscountType { get; set; }
[JsonIgnore]
public int Discount { get; set; }
}
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum DiscountType
{
Percentage,
Amount
}
}

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Route("/shapes")]
public class PolymorphicTypesController
{
[HttpPost]
public int CreateShape([FromBody]Shape shape)
{
throw new NotImplementedException();
}
[HttpGet]
public IEnumerable<Shape> GetShapes()
{
throw new NotImplementedException();
}
}
public abstract class Shape
{
public string Name { get; set; }
}
public class Rectangle : Shape
{
public int Height { get; set; }
public int Width { get; set; }
}
public class Circle : Shape
{
public int Radius { get; set; }
}
}

View File

@ -0,0 +1,35 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Route("/orders")]
[Consumes("application/xml")]
[Produces("application/xml")]
public class ResponseTypeAnnotationsController
{
/// <summary>
/// Creates an order
/// </summary>
/// <param name="order"></param>
/// <response code="201">Order created</response>
/// <response code="400">Order invalid</response>
[HttpPost]
[ProducesResponseType(typeof(int), 201)]
[ProducesResponseType(typeof(IDictionary<string, string>), 400)]
public IActionResult CreateOrder([FromBody, Required]Order order)
{
return new CreatedResult("/orders/1", 1);
}
}
public class Order
{
public int Id { get; set; }
public string Description { get; set; }
public decimal Total { get; set; }
}
}

View File

@ -0,0 +1,44 @@
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Annotations;
using Basic.Swagger;
namespace Basic.Controllers
{
[SwaggerTag("Manipulate Carts to your heart's content", "http://www.tempuri.org")]
public class SwaggerAnnotationsController
{
[HttpPost("/carts")]
[SwaggerOperation(OperationId = "CreateCart")]
[SwaggerResponse(201, "The cart was created", typeof(Cart))]
[SwaggerResponse(400, "The cart data is invalid")]
public Cart Create([FromBody, SwaggerRequestBody(Description = "The cart request body")]Cart cart)
{
return new Cart { Id = 1 };
}
[HttpGet("/carts/{id}")]
[SwaggerOperation(OperationId = "GetCart")]
[SwaggerOperationFilter(typeof(AddCartsByIdGetExternalDocs))]
public Cart Get([SwaggerParameter("The cart identifier")]int id)
{
return new Cart { Id = id };
}
[HttpDelete("/carts/{id}")]
[SwaggerOperation(
OperationId = "DeleteCart",
Summary = "Deletes a specific cart",
Description = "Requires admin privileges")]
public Cart Delete([FromRoute(Name = "id"), SwaggerParameter("The cart identifier")]int cartId)
{
return new Cart { Id = cartId };
}
}
[SwaggerSchema(Required = new[] { "Id" })]
public class Cart
{
[SwaggerSchema("The cart identifier", ReadOnly = true)]
public int Id { get; set; }
}
}

View File

@ -0,0 +1,50 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace Basic.Controllers
{
[Route("/stores")]
[Produces("application/json")]
public class UnboundParamsController
{
[HttpPost]
public int Create(Store store)
{
return 1;
}
[HttpGet]
public IEnumerable<Store> Search(string[] locations = null)
{
return new[]
{
new Store { Id = 1, Location = "Boston" },
new Store { Id = 1, Location = "Seattle" }
};
}
[HttpGet("{id}")]
public Store GetById(int id)
{
return new Store { Id = 1, Location = "Boston" };
}
[HttpPut("{id}")]
public void Update(int id, Store store)
{
}
[HttpDelete("{id}")]
public void Delete(int id)
{
}
}
public class Store
{
public int Id { get; set; }
public string Location { get; set; }
}
}

26
test/Basic/Program.cs Normal file
View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
namespace Basic
{
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}

View File

@ -0,0 +1,29 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:53224"
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Basic": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "",
"applicationUrl": "http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

125
test/Basic/Startup.cs Normal file
View File

@ -0,0 +1,125 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using Basic.Swagger;
using Microsoft.AspNetCore.Localization;
using System.IO;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System.Text.Json;
using System.Text.Json.Serialization;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Reflection;
using IGeekFan.AspNetCore.Knife4jUI;
namespace Basic
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1",
new OpenApiInfo
{
Title = "Test API V1",
Version = "v1",
Description = "A sample API for testing Swashbuckle",
TermsOfService = new Uri("http://tempuri.org/terms")
}
);
c.SwaggerDoc("gp", new OpenApiInfo { Title = "<22><>¼ģ<C2BC><C4A3>", Version = "GP" });
c.RequestBodyFilter<AssignRequestBodyVendorExtensions>();
c.OperationFilter<AssignOperationVendorExtensions>();
c.SchemaFilter<ExamplesSchemaFilter>();
c.DescribeAllParametersInCamelCase();
c.GeneratePolymorphicSchemas();
c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "Basic.xml"));
c.EnableAnnotations();
c.AddServer(new OpenApiServer()
{
Url = "",
Description = "vvv"
});
c.CustomOperationIds(apiDesc =>
{
return apiDesc.TryGetMethodInfo(out MethodInfo methodInfo) ? methodInfo.Name : null;
});
c.OrderActionsBy((apiDesc) => $"{apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.HttpMethod}");
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr"),
new CultureInfo("sv-SE"),
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
// Formatting numbers, dates, etc.
SupportedCultures = supportedCultures,
// UI strings that we have localized.
SupportedUICultures = supportedCultures
});
app.UseSwagger(c =>
{
});
app.UseKnife4UI(c =>
{
c.RoutePrefix = ""; // serve the UI at root
c.SwaggerEndpoint("/v1/api-docs", "V1 Docs");
c.SwaggerEndpoint("/gp/api-docs", "<22><>¼ģ<C2BC><C4A3>");
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapSwagger("{documentName}/api-docs");
});
}
}
}

View File

@ -0,0 +1,18 @@
using System;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Basic.Swagger
{
public class AddCartsByIdGetExternalDocs : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.ExternalDocs = new OpenApiExternalDocs
{
Description = "External docs for CartsByIdGet",
Url = new Uri("https://tempuri.org/carts-by-id-get")
};
}
}
}

View File

@ -0,0 +1,14 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Basic.Swagger
{
public class AssignOperationVendorExtensions : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Extensions.Add("x-purpose", new OpenApiString("test"));
}
}
}

View File

@ -0,0 +1,14 @@
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Basic.Swagger
{
public class AssignRequestBodyVendorExtensions : IRequestBodyFilter
{
public void Apply(OpenApiRequestBody requestBody, RequestBodyFilterContext context)
{
requestBody.Extensions.Add("x-purpose", new OpenApiString("test"));
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace Basic.Swagger
{
public class ExamplesSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
schema.Example = GetExampleOrNullFor(context.Type);
}
private IOpenApiAny GetExampleOrNullFor(Type type)
{
switch (type.Name)
{
case "Product":
return new OpenApiObject
{
[ "id" ] = new OpenApiInteger(123),
[ "description" ] = new OpenApiString("foobar"),
[ "price" ] = new OpenApiDouble(14.37)
};
default:
return null;
}
}
}
}

View File

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

View File

@ -0,0 +1,10 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}