Biwen.QuickApi 1.3.5

There is a newer version of this package available.
See the version list below for details.
dotnet add package Biwen.QuickApi --version 1.3.5
                    
NuGet\Install-Package Biwen.QuickApi -Version 1.3.5
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Biwen.QuickApi" Version="1.3.5" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Biwen.QuickApi" Version="1.3.5" />
                    
Directory.Packages.props
<PackageReference Include="Biwen.QuickApi" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Biwen.QuickApi --version 1.3.5
                    
#r "nuget: Biwen.QuickApi, 1.3.5"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Biwen.QuickApi@1.3.5
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Biwen.QuickApi&version=1.3.5
                    
Install as a Cake Addin
#tool nuget:?package=Biwen.QuickApi&version=1.3.5
                    
Install as a Cake Tool

Biwen.QuickApi

项目介绍

[QuickApi("hello/world")]
public class MyApi : BaseQuickApi<Req,Rsp>{}
  • (MinimalApi as REPR) Biwen.QuickApi遵循了 REPR 设计 (Request-Endpoint-Response)
  • 开箱即用的Api路由 和 权限,Bind,validator体验
  • 该库是NET WebApi/Minimal Api的补充,性能≈MinimalApi(gen版本=minimalApi,生成原生接口代码),遥遥领先于MVC和WebApi,但是提供了最简单的的使用体验
  • write less, do more ; write anywhere, do anything
  • 欢迎小伙伴们star&issue共同学习进步 (Biwen.QuickApi)[https://github.com/vipwan/Biwen.QuickApi]

SourceGenerator

  • 提供gen源代码生成器方案,以于显著提升性能(V1.0版本使用的Emit和dynamic会导致部分性能损失)
  • gen SourceGenerator已发布v1.1.2,使用方式

使用方式

Step0 Nuget Base & Generator

dotnet add package Biwen.QuickApi
dotnet add package Biwen.QuickApi.SourceGenerator

Step1 UseBiwenQuickApis


builder.Services.AddBiwenQuickApis();

//缺省方案
app.MapBiwenQuickApis();

//Gen方案
//app.MapGenBiwenQuickApis();

Step2 Define Request and Response


    public class HelloApiRequest : BaseRequest<HelloApiRequest>
    {
        public string? Name { get; set; }

        /// <summary>
        /// 别名绑定字段
        /// </summary>
        [AliasAs("a")]
        public string? Alias { get; set; }
        /// <summary>
        /// FromQuery特性绑定字段
        /// </summary>
        [FromQuery("q")]
        public string? Q { get; set; }
        public HelloApiRequest()
        {
            RuleFor(x => x.Name).NotNull().Length(5, 10);
        }
    }
    
    /// <summary>
    /// 上传文件FileUploadRequest 
    /// </summary>
    public class FileUploadRequest : BaseRequest<FileUploadRequest>
    {
        public IFormFile? File { get; set; }

        public FileUploadRequest()
        {
            RuleFor(x => x.File).NotNull();
        }
    }

    /// <summary>
    /// 模拟自定义绑定的Request
    /// </summary>
    public class CustomApiRequest : BaseRequest<CustomApiRequest>
    {
        public string? Name { get; set; }

        public CustomApiRequest()
        {
            RuleFor(x => x.Name).NotNull().Length(5, 10);
        }
    }
    /// <summary>
    /// 标记FromBody,表示这个请求对象是FromBody的
    /// </summary>
    [FromBody]
    public class FromBodyRequest : BaseRequest<FromBodyRequest>
    {
        public int Id { get; set; }
        public string? Name { get; set; }

        public FromBodyRequest()
        {
            RuleFor(x => x.Id).InclusiveBetween(1, 100);//必须1~100
        }
    }
    /// <summary>
    /// 自定义的绑定器
    /// </summary>
    public class CustomApiRequestBinder : IReqBinder<CustomApiRequest>
    {
        public async Task<CustomApiRequest> BindAsync(HttpContext context)
        {
            var request = new CustomApiRequest
            {
                Name = context.Request.Query["c"]
            };
            await Task.CompletedTask;
            return request;
        }
    }

    public class HelloApiResponse : BaseResponse
    {
        public string? Message { get; set; }
    }

Step3 Define QuickApi


    /// <summary>
    /// get ~/admin/index
    /// </summary>
    [QuickApi("index", Group = "admin", Verbs = Verb.GET | Verb.POST, Policy = "admin")]
    public class NeedAuthApi : BaseQuickApi
    {
        public override EmptyResponse Execute(EmptyRequest request)
        {
            return EmptyResponse.Instance;
        }
    }

    /// <summary>
    /// get ~/hello/world/{name}
    /// </summary>
    [QuickApi("world/{name}", Group = "hello", Verbs = Verb.GET | Verb.POST)]
    public class HelloApi : BaseQuickApi<HelloApiRequest, HelloApiResponse>
    {
        private readonly HelloService _service;
        private readonly IHttpContextAccessor _httpContextAccessor;

        public Hello4Api(HelloService service,IHttpContextAccessor httpContextAccessor)
        {
            _service = service;
            _httpContextAccessor = httpContextAccessor;
        }

        public override HelloApiResponse Execute(HelloApiRequest request)
        {
            var hello = _service.Hello($"hello world {_httpContextAccessor.HttpContext!.Request.Path} !");
            return new HelloApiResponse
            {
                Message = hello
            };
        }
    }

    /// <summary>
    /// get ~/custom?c=11112222
    /// </summary>
    [QuickApi("custom", Verbs = Verb.GET)]
    public class CustomApi : BaseQuickApi<CustomApiRequest>
    {
        public CustomApi()
        {
            //自定义绑定器
            UseReqBinder<CustomApiRequestBinder>();
        }

        public override async Task<EmptyResponse> ExecuteAsync(CustomApiRequest request)
        {
            await Task.CompletedTask;
            Console.WriteLine($"获取自定义的 CustomApi:,从querystring:c绑定,{request.Name}");
            return EmptyResponse.New;
        }

        /// <summary>
        /// 提供minimal扩展
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public override RouteHandlerBuilder HandlerBuilder(RouteHandlerBuilder builder)
        {
            //自定义描述
            builder.WithOpenApi(operation => new(operation)
            {
                Summary = "This is a summary",
                Description = "This is a description"
            });

            //自定义标签
            builder.WithTags("custom");

            //自定义过滤器
            builder.AddEndpointFilter(async (context, next) =>
            {
                Console.WriteLine("自定义过滤器!");
                return await next(context);
            });
            //默认实现了Accepts和Produces
            return base.HandlerBuilder(builder);
            //如果完全自定义直接返回Builder
            //return builder;
         }
    }

     /// <summary>
    /// 提供对IResult的封装支持
    /// </summary>
    [QuickApi("iresult", Verbs = Verb.GET)]
    public class IResultTestApi : BaseQuickApiWithoutRequest<IResultResponse>
    {
        public override async Task<IResultResponse> ExecuteAsync(EmptyRequest request)
        {
            return Results.Ok("Hello World IResult!").AsRsp();
        }

        public override RouteHandlerBuilder HandlerBuilder(RouteHandlerBuilder builder)
        {
            //针对IResultResponse,需要完全自定义Produces,QuickApi无法自动识别
            builder.Produces(200, typeof(string), contentType: "text/plain");
            return builder;
            //return base.HandlerBuilder(builder);
        }
    }
    

    /// <summary>
    /// 上传文件测试
    /// 请使用postman & apifox 测试
    /// </summary>
    [QuickApi("fromfile", Verbs = Verb.POST)]
    public class FromFileApi : BaseQuickApi<FileUploadRequest, IResultResponse>
    {
        public override async Task<IResultResponse> ExecuteAsync(FileUploadRequest request)
        {
            //测试上传一个文本文件并读取内容
            if (request.File != null)
            {
                using (var sr = new StreamReader(request.File.OpenReadStream()))
                {
                    var content = await sr.ReadToEndAsync();
                    return Results.Ok(content).AsRsp();
                }
            }
            return Results.BadRequest("no file").AsRsp();
        }

        public override RouteHandlerBuilder HandlerBuilder(RouteHandlerBuilder builder)
        {
            builder.Accepts<FileUploadRequest>("multipart/form-data");
            builder.WithOpenApi(operation => new(operation)
            {
                Summary = "上传文件测试",
                Description = "上传文件测试"
            });
            return builder;
        }
    }

    /// <summary>
    /// JustAsService 只会被服务发现,不会被注册到路由表
    /// </summary>
    [QuickApi(""), JustAsService]
    public class JustAsService : BaseQuickApi<EmptyRequest, ContentResponse>
    {
        public override Task<ContentResponse> ExecuteAsync(EmptyRequest request)
        {
            return Task.FromResult(new ContentResponse("Hello World JustAsService!"));
        }
    }

Step4 Enjoy !


//直接访问
// GET ~/hello/world/biwen
// GET ~/hello/world/biwen?name=biwen
// POST ~/hello/world/biwen
// GET ~/custom?c=11112222


//你也可以把QuickApi当Service使用
app.MapGet("/fromapi", async (Biwen.QuickApi.DemoWeb.Apis.Hello4Api api) =>
{
    //通过你的方式获取请求对象
    var req = new EmptyRequest();
    //验证请求对象
    var result = req.RealValidator.Validate(req);
    if (!result.IsValid)
    {
        return Results.BadRequest(result.ToDictionary());
    }
    //执行请求
    var x = await api.ExecuteAsync(new EmptyRequest());
    return Results.Ok(x);
});

Step5 OpenApi 以及Client代理

  • 你可以全局配置版本号,以及自定义的OpenApi描述
  • 你可以重写QuickApi的HandlerBuilder方法,以便于你自定义的OpenApi描述
  • 我们强烈建议您使用Refit生成代理代码,以便于您的客户端和服务端保持一致的接口定义
  • 因为遵循REPR风格,所以不推荐SwaggerUI或使用SwaggerStudio生成代理代码,除非您的QuickApi定义的相当规范(如存在自定义绑定,别名绑定等)!

/// <summary>
/// refit client
/// </summary>
public interface IBusiness
{
    [Refit.Get("/fromapi")]
    public Task<TestRsp> TestPost();
}

//Refit
builder.Services.AddRefitClient<IBusiness>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("http://localhost:5101"));

var app = builder.Build();

app.MapGet("/from-quickapi", async (IBusiness bussiness) =>
{
    var resp = await bussiness.TestPost();
    return Results.Content(resp.Message);
});

Q&A

  • 为什么不支持.NET6 -- 考虑到.NET8已经发布了RC,11月就会发布RTM,这个是未来3年的长期支持版本,并且.NET是可以无缝升级到.NET8的,所以我没有计划.NET6支持,直接拥抱新特性

  • 为什么不支持多个参数的绑定? -- 因为我认为这样的Api设计是不合理的,我们遵循REPR设计理念,如果你需要多个参数,请使用复杂化的Request对象

  • QuickApi中如何拿到HttpContext对象? -- 请在构造函数中注入IHttpContextAccessor获取

  • 是否支持Minimal的中间件和拦截器? -- 支持的,本身QuickApi就是扩展了MinimalApi,底层也是Minimal的处理机制,所以请考虑全局的中间件和拦截器,以及重写QuickApi的HandlerBuilder方法

Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (4)

Showing the top 4 NuGet packages that depend on Biwen.QuickApi:

Package Downloads
Biwen.QuickApi.FeatureManagement

Package Description

Biwen.QuickApi.Contents

Package Description

Biwen.QuickApi.MiniProfiler

Biwen.QuickApi ,NET9+ MinimalApi CQRS

Biwen.QuickApi.Storage.AliyunOss

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.5 243 5/14/2025
2.0.3 188 3/31/2025
2.0.2 147 2/18/2025
2.0.1 117 1/16/2025
2.0.0 163 11/13/2024
2.0.0-rc3 79 10/24/2024
2.0.0-rc2 81 9/26/2024
2.0.0-rc1 76 9/24/2024
1.6.3 131 8/29/2024
1.6.2 140 6/14/2024
1.6.1 143 5/22/2024
1.5.2.1 134 5/16/2024
1.5.2 144 5/15/2024
1.5.0 124 5/13/2024
1.4.3.2 136 5/10/2024
1.4.2.2 143 5/9/2024
1.4.2.1 140 4/10/2024
1.4.2 163 2/21/2024
1.4.1 253 12/8/2023
1.4.0 160 11/15/2023
1.3.8 156 11/9/2023
1.3.7.3 149 11/5/2023
1.3.7.2 164 11/2/2023
1.3.7.1 166 10/21/2023
1.3.7 162 10/19/2023
1.3.6 186 10/15/2023
1.3.5 163 10/12/2023
1.0.0 163 9/21/2023

权限控制特性