在 ASP.NET Core 中编写高性能 Web API 的4个小技巧
Web API 通常用来与外部模块进行通信、发送和接收数据,作为后端开发人员,应该把写出高性能的应用作为目标。
下面 4 个技巧是我在编写 Web API 的小技巧。
1 、大量数据使用分页查询
接口传输大量数据可能会导致严重的性能问题、过多的内存消耗和速度减慢。为了缓解这些可能的瓶颈,强烈建议使用分页查询。
分页查询允许请求者选择特定范围的值。
下面是在 ASP. NET Core 中实现分页的方法之一:
[HttpGet("error-logs/{skip}/{take}")]
public async Task<ActionResult<List<Log>>> GetErrorLogsPaginated([FromRoute] int skip = 0, [FromRoute] int take = 10)
{
var logErrors = await _context.Logs
.Where(l => l.LogLevel == InternalLogLevel.Error)
.Skip(skip)
.Take(take)
.OrderBy(c => c.Id)
.ToListAsync();
return Ok(logErrors);
}
2、减少网络往返次数
避免网络往返意味着应该尽可能在单个调用中查询必要数据,而不是进行多个调用,然后将它们放在一起。
[HttpGet("services-ids")]
public async Task<ActionResult<List<int>>> GetServicesIds()
{
var servicesIds = await _context.Services.AsNoTracking().Select(x => x.Id).ToListAsync();
return Ok(servicesIds);
}
[HttpGet("logs-with-service")]
public async Task<ActionResult<List<Log>>> GetLogsByServiceIds([FromQuery] List<int> serviceIds)
{
var logs = await _context.Logs
.AsNoTracking()
.Where(s => serviceIds.Contains(s.Id))
.Select(s => new Log
{
Id = s.Id,
Service = s.Service,
})
.ToListAsync();
return Ok(logs);
}
这里有两个接口,第一个接口返回了所有的服务 id,第二个接口返回包含具有这些 id 的记录的日志。在上面的示例中,需要进行两次调用,这是不建议的。
应该按照以下方式进行:
[HttpGet("logs-with-service")]
public async Task<ActionResult<List<Log>>> GetAllServicesWithLogs()
{
var services = await _context.Services
.AsNoTracking()
.ToListAsync();
var serviceIds = services.Select(s => s.Id).ToList();
var logs = await _context.Logs
.AsNoTracking()
.Where(l => serviceIds.Contains(l.ServiceId))
.ToListAsync();
return Ok(logs);
}
3、使用 Task 等待任务完成
使用 async Task 意味着请求管道可以等到异步方法完成。
ASP. NET Core 希望操作方法返回 Task,以便它可以正确继承到异步请求管道中。如果使用 async void,将会导致异步操作完成之前出现响应。
不要使用:async void
[HttpDelete("/{id}")]
public async void DeleteService([FromRoute] int id)
{
await _context.Services.FirstOrDefaultAsync(s => s.Id == id);
await Response.WriteAsync("Successfully deleted record");
}
应该用: async Task
[HttpDelete("/{id}")]
public async Task DeleteService([FromRoute] int id)
{
await _context.Services.FirstOrDefaultAsync(s => s.Id == id);
await Response.WriteAsync("Successfully deleted record");
}
4、对经常访问的数据使用缓存
缓存很有用,它是一种通过减少数据库资源消耗来显著提高应用程序性能的技术。
在第一次请求中,从数据库中检索数据并写入缓存。在后续的请求中,如果数据存在于缓存中,则会立即返回给请求者,而不需要查询数据库。
缓存最适合数据不经常更改的场景,ASP.NET Core 支持两种主要类型的缓存:内存缓存和分布式缓存。
内存缓存非常简单,通过 IMemoryCache 接口提供。IMemoryCache 表示存储在 Web 服务器内存中的缓存。
下面时一个使用内存缓存的示例:
[HttpGet("log-errors-cache-in-memory")]
public async Task<ActionResult<List<Log>>> GetErrorLogsWithCacheInMemory()
{
const string CacheKey = "logs_with_error";
if (!_memoryCache.TryGetValue(CacheKey, out List<Log>? logErrors))
{
logErrors = await _context.Logs
.Where(l => l.LogLevel == InternalLogLevel.Error)
.ToListAsync();
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(30));
_memoryCache.Set(CacheKey, logErrors, cacheEntryOptions);
}
return Ok(logErrors);
}
实现缓存的另一种方式是使用分布式缓存,它可以在多个服务器之间共享,并且通常作为外部服务部署维护。
ASP. NET Core 通过 IDistributedCache 接口提供分布式缓存处理方法,有 Redis、内存、SQL Server、NCache、Azure CosmosDB 多种实现。
要使用分布式缓存,你需要有一个运行的缓存服务实例。
下面的代码展示了一个使用分布式缓存的终端节点:
[HttpGet("log-errors-cache-distributed")]
public async Task<ActionResult<List<Log>>> GetErrorLogsWithCacheDistributed()
{
const string CacheKey = "logs_with_error";
List<Log>? logErrors = await _memcachedClient.GetValueAsync<List<Log>>(CacheKey);
if (logErrors == null)
{
logErrors = await _context.Logs
.Where(l => l.LogLevel == InternalLogLevel.Error)
.ToListAsync();
await _memcachedClient.SetAsync(CacheKey, logErrors, TimeSpan.FromMinutes(30));
}
return Ok(logErrors);
}
两端代码看起来非常相似,最大的区别在于缓存存储的位置。
在 ASP.NET Core 中编写高性能 Web API 的4个小技巧的更多相关文章
- 转自微软内部资料:编写高性能 Web 应用程序的 10 个技巧
编写高性能 Web 应用程序的 10 个技巧 转自微软资料数据层性能技巧 1 — 返回多个结果集技巧 2 — 分页的数据访问技巧 3 — 连接池技巧 4 — ASP.NET 缓存 API技巧 5 — ...
- 002.Create a web API with ASP.NET Core MVC and Visual Studio for Windows -- 【在windows上用vs与asp.net core mvc 创建一个 web api 程序】
Create a web API with ASP.NET Core MVC and Visual Studio for Windows 在windows上用vs与asp.net core mvc 创 ...
- 在ASP.NET Core中编写合格的中间件
这篇文章探讨了让不同的请求去使用不同的中间件,那么我们应该如何配置ASP.NET Core中间件?其实中间件只是在ASP.NET Core中处理Web请求的管道.所有ASP.NET Core应用程序至 ...
- 如何在ASP.NET Core中编写高效的控制器
通过遵循最佳实践,可以编写更好的控制器.所谓的"瘦"控制器(指代码更少.职责更少的控制器)更容易阅读和维护.而且,一旦你的控制器很瘦,可能就不需要对它们进行太多测试了.相反,你可 ...
- 编写高性能Web应用程序的10个技巧
这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...
- 编写高性能 Web 应用程序的 10 个技巧
使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信.正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了.在本文中,我将讲述 10 个用于编写高性能 ...
- 如何设计出和 ASP.NET Core 中 Middleware 一样的 API 方法?
由于笔者时间有限,无法写更多的说明文本,且主要是自己用来记录学习点滴,请谅解,下面直接贴代码了(代码中有一些说明): 01-不好的设计 代码: using System; namespace Desi ...
- 使用依赖关系注入在 ASP.NET Core 中编写干净代码
ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主要目标之一就是更多的模块化设计.即,应用应该能够仅利用其所需的框架部分,方法是框架在它们请求时提供依赖关系.此外,使 ...
- [转]使用依赖关系注入在 ASP.NET Core 中编写干净代码
本文转自:http://blog.jobbole.com/101270/ 原文出处: Steve Smith ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主 ...
- ASP.NET Core 1.0开发Web API程序
.NET Core版本:1.0.0-rc2Visual Studio版本:Microsoft Visual Studio Community 2015 Update 2开发及运行平台:Windows ...
随机推荐
- h5按需引入Vant
下载按需引入插件(推荐) babel-plugin-import 是一款 babel 插件, 它会在编译过程中将 import 的写法自动转换为按需引入的方式 # 安装插件 npm i babel-p ...
- Windows中安装和配置Maven
1.下载 下载地址:https://maven.apache.org/download.cgi 下载文件:https://dlcdn.apache.org/maven/maven-3/3.9.6/bi ...
- .NET 进程 stackoverflow异常后,还可以接收 TCP 连接请求吗?
昨天线上有几个进程因为 StackOverFlowException 导致进程 Crash 了,但是 TCP 请求还是可以连接,具体可不可以连接一个出现StackOverFlowException的微 ...
- 网口CE超标了~
前不久遇到一个网口传导测试超标的问题,今天在此分享下,希望各位能有所收获~ 背景 在对量产产品EMC抽检时,发现网口CE测试在537KHz处超标2.84dB 因为是网口传导测试,所以首先检查与网口相关 ...
- ATT&CK实战系列(二)红日靶场2
拓扑图 导入虚拟机 网络配置 增加网卡 配置网卡 三台主机的密码均为1qaz@WSX,其中WEB在登录的时候需要切换用户de1ay登录 iP地址 DC PC 配置PC和WEB主机时,会弹框输入admi ...
- [HNOI2009] 图的同构计数
因为要求本质不同的图,容易想到群论. 为了方便处理,将边是否存在转化为边的黑白染色问题(实际上就是 \([SHOI2006]\) 有色图 的弱化版本,最终公式也差不多). 根据 \(Burnside\ ...
- 安川MOTOMAN机器人NX100维修的注意事项
安川MOTOMAN机器人NX100维修,操作人员安全注意事项 整个机器人的最大动作范围内均具有潜在的危险性. 为机器人工作的所有人员 (安全管理员.安装人员.操作人员和机器人维修人员) 必须时刻树 ...
- es5经典数组去重
es5经典数组去重 for (var i = 0; i < arr.length; i++) { for (var j = 1; j < arr.length; j++) { if (ar ...
- 保持Android Service在手机休眠后继续运行的方法
保持Android Service在手机休眠后继续运行的方法 下面小编就为大家分享一篇保持Android Service在手机休眠后继续运行的方法,具有很好的参考价值,希望对大家有所帮助.一起跟随 ...
- QT5笔记: 8. QT的全局变量(基本数据类型、函数、宏)
这个头文件中存放着QT类库的一些全局定义,一般Qt类的头文件会包含这个头文件: 基本数据类型 函数 宏 数据类型:保证跨平台时各数据类型长度统一 函数定义(一些数学函数未在QtGlobal中,而是在Q ...