.NET7 Preview4 之OpenAPI swagger改进

简介: .NET7 Preview4 之OpenAPI swagger改进

.NET7 Preview4 之OpenAPI swagger改进


在MiniAPI系列中,《.NET6之MiniAPI(十八):OpenAPI swagger》介绍了swagger在MiniAPI框架中的使用,当时留下很多不足,随着.NET7 Preview4的推出,这方面得到了很大的改进,我还是使用“十八”这篇文章的案例。

如果想参看原来文章,见下面引用:

此次对OpenAPI的提升主要是通过命名空间Microsoft.AspNetCore.OpenApi带来的。

新建API项目,选用minimal api模板,并带有OpenAPI,同时在Nuget升级Swashbuckle.AspNetCore为6.3.1以后的版本,核心代码如下:

using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.AspNetCore.OpenApi;
using Microsoft.OpenApi.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1",
       new OpenApiInfo
       {
           Title = "MiniAPI7_new04-V1",
           Version = "v1"
       }
    );
    //添加授权
    var schemeName = "Bearer";
    c.AddSecurityDefinition(schemeName, new OpenApiSecurityScheme
    {
        In = ParameterLocation.Header,
        Description = "请输入不带有Bearer的Token",
        Name = "Authorization",
        Type = SecuritySchemeType.Http,
        Scheme = schemeName.ToLowerInvariant(),
        BearerFormat = "JWT"
    });
    c.AddSecurityRequirement(new OpenApiSecurityRequirement {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = schemeName
                            }
                        },
                        new string[0]
                    }
                });
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.EnablePersistAuthorization();
    });
}
//增
app.MapPost("/test", Results<Ok<Data>, NotFound> (Data data) =>
{
    if (data != null)
    {
        data.ID = 101;
        return TypedResults.Ok(data);
    }
    else
    {
        return TypedResults.NotFound();
    }
})
.WithTags("all test")
.WithOpenApi(operation =>
{
    operation.Description = "这是一个神密的功能,用来实现添加";
    operation.Summary = "添加Data";
    operation.Parameters.Clear();
    operation.RequestBody = new OpenApiRequestBody
    {
        Description = "添加的数据实体",
        Required = true,
        Content = new Dictionary<string, OpenApiMediaType>
        {
            {
                "application/json", new OpenApiMediaType
                {
                    Schema = new OpenApiSchema
                    {
                        Type = "object",
                        Properties = new Dictionary<string, OpenApiSchema>
                        {
                            {"ID",new OpenApiSchema{ Type="integer" } },
                            {"Name",new OpenApiSchema{ Type="string" } },
                            {"Token",new OpenApiSchema{ Type="string" } }
                        },
                    },
                }
            }
        },
    };
    return operation;
});
//删
app.MapDelete("/test/{id}", Results<Ok, NotFound> (int? id) =>
{
    if (id.HasValue)
    {
        return TypedResults.Ok();
    }
    else
    {
        return TypedResults.NotFound();
    }
})
.WithTags("all test")
.WithOpenApi(operation =>
{
    operation.Description = "这是一个神密的功能,用来实现删除";
    operation.Summary = "按编号删除";
    operation.Parameters[0].Description = "编号";
    operation.Parameters[0].AllowEmptyValue = true;
    return operation;
});
//改
app.MapPut("/test", (Data data) =>
{
})
.WithTags("all test")
.WithOpenApi(operation =>
{
    operation.Description = "这是一个神密的功能,用来实现修改";
    operation.Summary = "修改Data";
    operation.Parameters.Clear();
    return operation;
});
//查
app.MapGet("/test/{id}", Results<Ok<Data>, NotFound> (HttpRequest request, int? id) =>
{
    if (id.HasValue)
    {
        return TypedResults.Ok(new Data() { ID = id.Value, Name = "测试", Token = request.Headers["Authorization"] });
    }
    else
    {
        return TypedResults.NotFound();
    }
})
.WithTags("all test")
.WithOpenApi(operation =>
 {
     operation.Description = "这是一个神密的功能,用来实现查询";
     operation.Summary = "按编号查询";
     operation.Parameters[0].Description = "编号";
     operation.Parameters[0].AllowEmptyValue = true;
     return operation;
 });
app.Run();
/// <summary>
/// 提交数据
/// </summary>
class Data
{
    /// <summary>
    /// 编号 
    /// </summary>
    public int ID { get; set; }
    /// <summary>
    /// 名称
    /// </summary>
    public string? Name { get; set; }
    /// <summary>
    /// Token
    /// </summary>
    public string? Token { get; set; }
}

当年在做go时,很羡慕它的时间有微秒,纳秒,在做性能优化时,能很小颗粒度的查看引入方法执行的时间,当时.net的DateTime只有毫秒(虽然也有别的办法获取)。现在,在最新的.NET7 Preview4中,DateTime也有微秒和纳秒了,倍感亲切。

纳秒在百位上,没有十位和个位,但这也说明.NET在进化,向高性能进化,在乎微秒和百位纳秒了(哈哈)。

下面是引入这两个时间单位的实现:

namespace System {
    public struct DateTime {
        public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond);
        public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.DateTimeKind kind);
        public DateTime(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.Globalization.Calendar calendar);
        public int Microsecond { get; }
        public int Nanosecond { get; }
        public DateTime AddMicroseconds(double value);
    }
    public struct DateTimeOffset {
        public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.TimeSpan offset);
        public DateTimeOffset(int year, int month, int day, int hour, int minute, int second, int millisecond, int microsecond, System.TimeSpan offset, System.Globalization.Calendar calendar);
        public int Microsecond { get; }
        public int Nanosecond { get; }
        public DateTimeOffset AddMicroseconds(double microseconds);
    }
    public struct TimeSpan {
        public const long TicksPerMicrosecond = 10L;
        public const long NanosecondsPerTick = 100L;
        public TimeSpan(int days, int hours, int minutes, int seconds, int milliseconds, int microseconds);
        public int Microseconds { get; }
        public int Nanoseconds { get; }
        public double TotalMicroseconds { get; }
        public double TotalNanoseconds { get; }
        public static TimeSpan FromMicroseconds(double microseconds);
    }
    public struct TimeOnly {
        public TimeOnly(int day, int hour, int minute, int second, int millisecond, int microsecond);
        public int Microsecond { get; }
        public int Nanosecond { get; }
    }
}

.NET Preview5中,给MiniAPI带来了一个参数绑定的功能,看到这个功能,我一下子就开心了,因为它提供了一个把松散的传入数据或注入功能耦合在一起的能力,并且可以根据自己的需求自由组合,结合上原来的Fromxxx(Name=“”)]使用,尤其和谐。

看一下下面的例子,如果每个请求都带有X-UUID,可以直接放在父类里,这样的组合是不是更加灵活多变。

using Microsoft.AspNetCore.Mvc;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/test", ([AsParameters] Order order) =>
{
    order.Logger?.LogInformation(order.UUID);
});
app.Run();
class Header
{
    [FromHeader(Name = "X-UUID")]
    public string? UUID { get; set; }
}
class Order : Header
{
    [FromQuery(Name = "no")]
    public int OrderNo { get; set; }
    public ILogger<Order>? Logger { get; set; }
}

绑定的参数,不只是class,还可以是其他自定义类型。

结构

struct Order 
{
    [FromHeader(Name = "X-UUID")]
    public string? UUID { get; set; }
    [FromQuery(Name = "no")]
    public int OrderNo { get; set; }
    public ILogger<Order>? Logger { get; set; }
}

记录

record Order 
{
    [FromHeader(Name = "X-UUID")]
    public string? UUID { get; set; }
    [FromQuery(Name = "no")]
    public int OrderNo { get; set; }
    public ILogger<Order>? Logger { get; set; }
}

结构记录

record struct Order 
{
    [FromHeader(Name = "X-UUID")]
    public string? UUID { get; set; }
    [FromQuery(Name = "no")]
    public int OrderNo { get; set; }
    public ILogger<Order>? Logger { get; set; }
}
虽然这只是.NET的一小步,但给开发人员带了一大步,使整个API开发体验得到了,特别对数据接收体验提升了一大截。


目录
相关文章
|
26天前
|
开发框架 .NET 测试技术
了解 .NET 9 中的新 Microsoft.AspNetCore.OpenApi 包,并将其与 NSwag 和 Swashbuckle.AspNetCore 进行比较。
本文介绍了 `.NET 9` 中新推出的 `Microsoft.AspNetCore.OpenApi` 包,该包旨在为 `ASP.NET Core` 应用程序生成 `OpenAPI` 文档。文章对比了 `NSwag` 和 `Swashbuckle.AspNetCore` 两大现有库,探讨了新包的优势和不足,特别是在性能和功能方面。尽管新包在某些方面尚不及成熟库完善,但其对原生 `AoT` 编译的支持和未来的扩展潜力使其成为一个值得考虑的选择。文章还提供了详细的性能测试数据和优化建议,适合对 `OpenAPI` 文档生成感兴趣的开发者阅读。
60 3
了解 .NET 9 中的新 Microsoft.AspNetCore.OpenApi 包,并将其与 NSwag 和 Swashbuckle.AspNetCore 进行比较。
|
3月前
|
XML 开发框架 .NET
ASP.NET Web Api 如何使用 Swagger 管理 API
ASP.NET Web Api 如何使用 Swagger 管理 API
107 1
C# .net webapi使用swagger时显示controller注释
C# .net webapi使用swagger时显示controller注释
224 0
|
5月前
|
JSON 中间件 Java
中间件中OpenAPI (Swagger)
【6月更文挑战第3天】
83 4
|
6月前
|
JSON 安全 Java
如何基于 Swagger 使用 OpenAPI Generator生成 JMeter 脚本
【2月更文挑战第24天】如何基于 Swagger 使用 OpenAPI Generator生成 JMeter 脚本
286 0
如何基于 Swagger 使用 OpenAPI Generator生成 JMeter 脚本
|
6月前
|
XML API 数据库
七天.NET 8操作SQLite入门到实战 - 第六天后端班级管理相关接口完善和Swagger自定义配置
七天.NET 8操作SQLite入门到实战 - 第六天后端班级管理相关接口完善和Swagger自定义配置
128 0
|
开发框架 安全 中间件
Asp.Net Core遇到Swagger(五)-Swashbuckle-Jwt篇
Asp.Net Core遇到Swagger(五)-Swashbuckle-Jwt篇
160 0
Asp.Net Core遇到Swagger(五)-Swashbuckle-Jwt篇
|
开发框架 .NET 中间件
Swagger的 ASP.NET Core Web API 帮助页
使用 Web API 时,了解其各种方法对开发人员来说可能是一项挑战。 Swagger 也称为OpenAPI,解决了为 Web API 生成有用文档和帮助页的问题。 它具有诸如交互式文档、客户端 SDK 生成和 API 可发现性等优点。
104 0
|
开发框架 中间件 .NET
Swashbuckle源码应用之最后一次修改Swagger中OpenApi.json机会
Swashbuckle源码应用之最后一次修改Swagger中OpenApi.json机会
100 0
|
JSON 开发框架 安全
Asp.Net Core遇到Swagger(四)-Swashbuckle技巧c篇(下)
Asp.Net Core遇到Swagger(四)-Swashbuckle技巧c篇(下)
210 0