在我们开发项目的Web API的时候,随着项目功能要求越来越多,可能我们会为控制器基类增加越来越多的基础功能,有些功能有一定的适应性,但可能在一般的子类中用不到,而随着对控制器控制要求越来越精细,那么需要为基类或者子类增加更多的控制功能,这样随着迭代的进行,有些控制器的功能会显得越来越笨重。这个时候,一种更加灵活、轻便的Web API处理方式,对每个控制器方法的垂直切割的API框架应运而生,本篇随笔介绍的FastEndpoints 就是其中这样的一款框架,本篇随笔介绍一些FastEndpoints的基础处理方法,并通过一些基础的案例,把我们《 SqlSugar 开发框架》的一些模块进行迁移性测试,对比相关后端Web API的处理,一起分享给大家。

1、FastEndpoints介绍

FastEndpoints 是Minimal API和MVC的开发人员友好替代品,它是基于REPR设计模式(请求-端点-响应),以便创建方便且可维护的端点,几乎没有样板文件。

FastEndpoints 的性能与Minimal API 相当,甚至它更快,使用更少的内存并且每秒请求数比基准测试中的MVC控制器更高。对于比如:中间件、认证、授权、日志,依赖注入这些常用功能都支持,甚至有些还进行了加强。

设计主要是分为两种模式

分层模式:mvc、mvp、mvvm等
垂直模式:REPR设计模式
REPR设计模式就是垂直模式,系统的每个组件都是单独的一块,彼此并不影响,就像微服务那样。

MVC - 模型-视图-控制器旨在与用户界面配合使用。显然,视图是一个 UI 组件。如果您正在构建 API,则没有视图,因此您充其量使用的是 MC 模式,或者您可以将其称为模型-操作-控制器并获取 MAC 模式。关键是,你已经没有将MVC用于你的API,所以考虑一个更合适的模式应该不是一个很大的问题。

API 端点是非常独立的,每个端点都可以使用三个组件来描述:

请求(Request):终结点所需的数据形状
终结点(Endpoint):终结点在给定请求时执行的逻辑
响应(Response):终结点返回给调用方的响应
结合这三个元素,你会得到请求-端点-响应或 REPR 模式。

并非所有终结点都需要其请求或响应的实际数据,在某些情况下,不接收任何输入或仅返回 HTTP 状态代码。但是,在此模式中,空请求或响应仍然是有效的请求或响应,就像某些 MVC 操作不需要模型一样。

使用 API 端点库时,您可以将请求、终端节点和响应类型分组在一起,这样就无需在某些“视图模型”或“dtos”文件夹中四处寻找合适的类型。它减少了摩擦,使使用单个端点变得更加容易。

FastEndPoint GitHub库:https://github.com/FastEndpoints/FastEndpoints

FastEndpoints 在线文档:https://fast-endpoints.com

2、简单例子入门

参考官方的文档介绍,我们可以很容易的创建出一个简单的类似Hello开篇的API应用。

我创建一个基于.net core的Web API项目,先把FastEndPoint的相关引用加入项目中,如下所示。

然后在项目中的启动类代码中,我们添加相关的代码使用FastEndpoints,如下所示。

using FastEndpoints;
using FastEndpoints.Swagger; var bld = WebApplication.CreateBuilder();
bld.Services
.AddFastEndpoints()
.SwaggerDocument(); var app = bld.Build();
app.UseFastEndpoints()
.UseSwaggerGen();
app.Run();

如果需要对Swagger进行一些定制修改,可以改动如下,这里先忽略。

    .SwaggerDocument(o =>
{
o.DocumentSettings = s =>
{
s.Title = "SqlSugar框架接口API文档";
s.Version = "v1";
};
o.TagDescriptions = t =>
{
t["Test"] = "测试接口";
t["User"] = "用户相关接口";
};
})

为了简便,我们以命名控件不同,以及目录,来区分不同的Web API分组,如下所示,我们创建一个基于Test的相关API接口。

对于以前的控制器接口来说,一般可能一个控制(如TestController)会包含多个方法,如上面的Create、List方法,这里使用的是FastEndpoints,它们是把一个大型的控制器切换为一个方法一个类来处理,碎片化意味着类的增加,不过我们不需要做太多的工作,可以通过它们的一些基类来简化这个过程。

我们把WebAPI中请求的Request和Response的对象,放在一个Model类文件里面,如下代码所示。

namespace FastWebApi.Controllers.Test
{
/// <summary>
/// 测试请求信息
/// </summary>
public class TestRequest
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
} /// <summary>
/// 测试返回信息
/// </summary>
public class TestResponse
{
public string FullName { get; set; }
public bool IsOver18 { get; set; }
}
}

我们来看看基于FastEndPoints方式 生成一个Create的请求Web API方法,如下代码所示

namespace FastWebApi.Controllers.Test
{
//客户使用标识,不用覆盖 Configure 函数
//[HttpPost("/api/user/create")]
//[AllowAnonymous] /// <summary>
/// 创建记录
/// </summary>
public class Create : Endpoint<TestRequest, AjaxResponse>
{
public override void Configure()
{
Post("/test/create");
AllowAnonymous();
} public override async Task HandleAsync(TestRequest req, CancellationToken ct)
{
var result = new TestResponse()
{
FullName = req.FirstName + " " + req.LastName,
IsOver18 = req.Age > 18
};
await SendAsync(result.ToAjaxResponse());
}
}
}

我们配置Web API方法的路由,可以通过在Configure函数中指定: Post("/test/create")

也可以通过Attribute属性标识的方式,来声明,上面的注释代码所示。

[HttpPost("/api/user/create")]

这两者是等同的,任何一种方式都可以,默认的接口是需要授权才能访问的,如果我们标识了

[AllowAnonymous]

就可以匿名访问Web API 的方法了,Web API的方法处理逻辑,都是统一通过重写 HandleAsync 方法进行实现的,如上面代码所示。

其中AjaxResponse 是我定义的一个统一返回结果,这样我们的接口模型就一致了。

如下是Web API统一封装后返回的结果对象。

如果需要了解我的《SqlSugar开发框架》的统一结果返回处理,可以参考《基于SqlSugar的数据库访问处理的封装,在.net6框架的Web API上开发应用》中的 【统一结果封装和异常处理】 部分内容即可。

如果不需要统一返回模型,则可以自定义为任何的返回类型,如下是官方的案例所示。

public class MyEndpoint : Endpoint<MyRequest, MyResponse>
{
public override void Configure()
{
Post("/api/user/create");
AllowAnonymous();
} public override async Task HandleAsync(MyRequest req, CancellationToken ct)
{
await SendAsync(new()
{
FullName = req.FirstName + " " + req.LastName,
IsOver18 = req.Age > 18
});
}
}

接下来,我们检查下.netcore项目的launchSettings.json 配置信息

确保打开的时候就启动Swagger页面即可。

启动Swagger页面,我们来看看具体的效果,可以看到有两个Test的接口,如下所示。

我们来调试Swagger,并测试下结果返回。

测试返回的结果如下所示,由于采用了统一返回结果的处理,这里返回的TestResponse的对象序列化信息,放在了result的里面了,如下所示。

而List的控制器方法,这里没有请求输入的对象信息,因此参数为空。具体的API方法定义如下所示。

namespace FastWebApi.Controllers.Test
{
/// <summary>
/// 获取所有记录
/// </summary>
[HttpGet("/test/list")]
[AllowAnonymous]
public class List : EndpointWithoutRequest<AjaxResponse>
{
/// <summary>
/// 处理返回
/// </summary>
public override async Task HandleAsync(CancellationToken ct)
{
var result = new List<TestResponse>()
{
new TestResponse
{
FullName= "test",
IsOver18 = true,
},
new TestResponse
{
FullName= "test 2",
IsOver18 = false,
}
};
await SendAsync(result.ToAjaxResponse());
}
}
}

Swagger接口展示界面效果。

正常执行返回结果如下所示。

如果处理过程中有异常,由于我们采用了统一返回结果处理,因此异常信息也需要统一在对象里面,返回结果如下所示。

以上就是简单类型的一些处理例子,结合了统一返回结果的处理,我们可以很好的定义一个通用的结果返回。

3、对我们SqlSugar框架常规CRUD等基类接口进行垂直切割的处理

上面我们为了更好理解FastEndpoints的碎片化接口的处理,我们做了两个简单的方法来测试。

下面我们通过对我们SqlSugar开发框架中的基类接口进行功能上的拆分,并结合实际业务的需要接口,进行扩展的处理,从而也实现了常规CRUD的操作接口,并实现特殊业务类的API接口处理。

关于Web API的常规接口处理 ,我们为了简化代码,往往抽象一些常规的CRUD方法在控制器基类中,这样可以极大的减少了继承子类的接口代码,通过继承基类,子类自动具备了CRUD的处理接口,只需要根据业务的需要,增加一些特殊的业务接口即可。

以前的处理方法,我们是根据项目的需要,我们定义了一些控制器的基类,用于实现不同的功能,如下界面所示。

其中ControllerBase是.net core Web API中的标准控制器基类,我们由此派生一个LoginController用于登录授权,而BaseApiController则处理常规接口用户身份信息,而BusinessController则是对标准的增删改查等基础接口进行的封装,我们实际开发的时候,只需要开发编写类似CustomerController基类即可。

而现在采用FastEndpoints ,需要垂直切割整个控制器,我们需要把基类的接口实现放到具体的业务API类里面,我们为了方便,可以给他们不同的名称一个接口,或者组合在一个文件里面,如下所示。

我们来看看其中给一个简单的Count方法接口实现。

namespace FastWebApi.Controllers.User
{
/// <summary>
/// 根据条件计算记录数量
/// </summary>
[HttpGet("/user/count")]
public class Count : Endpoint<UserPagedDto, AjaxResponse>
{
/// <summary>
/// 处理请求
/// </summary>
public override async Task HandleAsync(UserPagedDto req, CancellationToken ct)
{
var result = await BLLFactory<IUserService>.Instance.CountAsync(req);
await SendAsync(result.ToAjaxResponse());
}
}
}

这里可以采用接口注入的方式,也可以采用我们辅助类BLLFactory<IUserService>.Instance方法调用接口,一样的实现。

这样结合了业务的具体Service来处理,只需要简单的处理下即可,也算比较方便,由于这些基础的CRUD的方法,主要路由、分页对象,业务对象,主键类型的不同,这些可以通过我们的代码生成工具的处理快速生成即可,因此可以实现批量化的业务类的API接口方法生成。

至于具体的业务接口API,我们就需要手工处理了,如对于用户的登陆获取token的方法,我们这里需要模仿来生成一个EndPiont类,如下所示。

    /// <summary>
/// 根据用户名、密码验证用户身份有效性
/// </summary>
[HttpPost("/user/verify-user")]
[AllowAnonymous]
public class VerifyUser : Endpoint<VerifyUserDto, AjaxResponse>
{
/// <summary>
/// 处理请求
/// </summary>
public override async Task HandleAsync(VerifyUserDto input, CancellationToken ct)
{
var result = await BLLFactory<IUserService>.Instance.VerifyUser(input.UserName, input.UserPassword, input.SystemType, input.IP, input.MacAddr);
await SendAsync(result.ToAjaxResponse());
}
}

其他业务方法也是类似的处理,这里的FastEndPoints的处理类,只是增加了一个简单的包装层就可以了,最后看看这些方法在SwaggerUI中的展示,和我们普通模式的Web API中的Swagger UI界面类似的效果。

这样,我们可以在保持接口一致性的情况下,无缝的对接新的Web API接口后端了。

使用 FastEndpoints 来垂直切换Web API的控制器方法的更多相关文章

  1. 8 种提升 ASP.NET Web API 性能的方法

    ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没有在应用程序结构设计上花时间来获得很好的执行性能. 在本文中,我将介绍8项提高 ASP.NET Web ...

  2. 如何让ASP.NET Web API的Action方法在希望的Culture下执行

    在今天编辑推荐的<Hello Web API系列教程--Web API与国际化>一文中,作者通过自定义的HttpMessageHandler的方式根据请求的Accep-Language报头 ...

  3. Web APi之控制器选择Action方法过程(九)

    前言 前面我们叙述了关于控制器创建的详细过程,在前面完成了对控制器的激活之后,就是根据控制器信息来查找匹配的Action方法,这就是本节要讲的内容.当请求过来时首先经过宿主处理管道然后进入Web AP ...

  4. Web APi之控制器创建过程及原理解析(八)

    前言 中秋歇了歇,途中也时不时去看看有关创建控制器的原理以及解析,时间拖得比较长,实在是有点心有余而力不足,但又想着既然诺下了要写完原理一系列,还需有始有终.废话少说,直入主题. HttpContro ...

  5. 8种提升ASP.NET Web API性能的方法

    英文原文:8 ways to improve ASP.NET Web API performance ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没 ...

  6. [转载]8 种提升 ASP.NET Web API 性能的方法

    http://www.oschina.net/translate/8-ways-improve-asp-net-web-api-performance 英文原文:8 ways to improve A ...

  7. 8 种提升 ASP.NET Web API 性能的方法 (转)

    出处:http://www.oschina.net/translate/8-ways-improve-asp-net-web-api-performance ASP.NET Web API 是非常棒的 ...

  8. 8 种提升ASP.NET Web API性能的方法

    ASP.NET Web API 是非常棒的技术.编写 Web API 十分容易,以致于很多开发者没有在应用程序结构设计上花时间来获得很好的执行性能. 在本文中,我将介绍8项提高 ASP.NET Web ...

  9. 8种提升 ASP.NET Web API 性能的方法

  10. 在基于MVC的Web项目中使用Web API和直接连接两种方式混合式接入

    在我之前介绍的混合式开发框架中,其界面是基于Winform的实现方式,后台使用Web API.WCF服务以及直接连接数据库的几种方式混合式接入,在Web项目中我们也可以采用这种方式实现混合式的接入方式 ...

随机推荐

  1. 如何调用api接口获取到商品数据

    要调用API接口获取商品数据,需要进行以下步骤: 确定API接口 首先需要确定要使用的API接口,可以通过搜索引擎或者相关文档来查找适合的API接口.以淘宝开放平台为例,可以使用淘宝的商品信息查询AP ...

  2. 京东获得JD商品详情 API 返回值说明

    ​ item_get-获得JD商品详情  API测试 onebound.jd.item_get 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) ...

  3. vue列表逐个进入过渡动画

    vue实现列表依次逐渐进入动画 利用vue 中transition-group 实现列表逐个进入动画效果 1.vue3代码, <template> <section class=&q ...

  4. Nomad 系列-快速上手

    系列文章 Nomad 系列文章 Nomad 重要术语 Nomad 安装设置相关术语 agent - 代理.Agent 是在 Server(服务器) 或 Client(客户端) 模式下运行的 Nomad ...

  5. Eclipse修改Web项目名称

    Eclipse修改Web项目名称需要两步: 1:修改该项目目录下:.project文件 <projectDescription><name>SpringMVC-Annotati ...

  6. [htmlayout] flow布局

    css { flow:xxxx.... } flow: vertical --------------------- 默认值, 块元素的所有子元素从上到下. flow: horizontal ---- ...

  7. The Missing Semester - 第五讲 学习笔记(二)

    第五讲(二) SSH入门 介绍完命令行环境后,这半节主要介绍的是ssh的有关入门知识.SSH是Secure Shell的简称. 课程视频地址:https://www.bilibili.com/vide ...

  8. 「codeforces - 1608F」MEX counting

    link. 首先考虑暴力,枚举规划前缀 \([1, i]\) 和前缀 mex \(x\),则我们需要 \(x\) 个数来填了 \([0, x)\),还剩下 \(i-x\) 个数随便填 \([0, x) ...

  9. 「acmhdu - 6314」Matrix

    link. 首先将问题弱化为 1-d,我们待定容斥系数 \(f_i\),可以写出答案的式子:\(\sum\limits_{i=a}^nf_i\binom{n}{i}2^{n-i}\).解释就是,我们想 ...

  10. Solution -「洛谷 P5610」「YunoOI 2013」大学

    Description Link. 区间查 \(x\) 的倍数并除掉,区间查和. Solution 平衡树. 首先有个基本的想法就是按 \(a_{i}\) 开平衡树,即对于每个 \(a_{i}\) 都 ...