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个小技巧的更多相关文章

  1. 转自微软内部资料:编写高性能 Web 应用程序的 10 个技巧

    编写高性能 Web 应用程序的 10 个技巧 转自微软资料数据层性能技巧 1 — 返回多个结果集技巧 2 — 分页的数据访问技巧 3 — 连接池技巧 4 — ASP.NET 缓存 API技巧 5 — ...

  2. 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 创 ...

  3. 在ASP.NET Core中编写合格的中间件

    这篇文章探讨了让不同的请求去使用不同的中间件,那么我们应该如何配置ASP.NET Core中间件?其实中间件只是在ASP.NET Core中处理Web请求的管道.所有ASP.NET Core应用程序至 ...

  4. 如何在ASP.NET Core中编写高效的控制器

    ​通过遵循最佳实践,可以编写更好的控制器.所谓的"瘦"控制器(指代码更少.职责更少的控制器)更容易阅读和维护.而且,一旦你的控制器很瘦,可能就不需要对它们进行太多测试了.相反,你可 ...

  5. 编写高性能Web应用程序的10个技巧

    这篇文章讨论了: ·一般ASP.NET性能的秘密 ·能提高ASP.NET表现的有用的技巧和窍门 ·在ASP.NET中使用数据库的建议 ·ASP.NET中的缓存和后台处理 使用ASP.NET编写一个We ...

  6. 编写高性能 Web 应用程序的 10 个技巧

    使用 ASP.NET 编写 Web 应用程序的简单程度令人不敢相信.正因为如此简单,所以很多开发人员就不会花时间来设计其应用程序的结构,以获得更好的性能了.在本文中,我将讲述 10 个用于编写高性能 ...

  7. 如何设计出和 ASP.NET Core 中 Middleware 一样的 API 方法?

    由于笔者时间有限,无法写更多的说明文本,且主要是自己用来记录学习点滴,请谅解,下面直接贴代码了(代码中有一些说明): 01-不好的设计 代码: using System; namespace Desi ...

  8. 使用依赖关系注入在 ASP.NET Core 中编写干净代码

    ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主要目标之一就是更多的模块化设计.即,应用应该能够仅利用其所需的框架部分,方法是框架在它们请求时提供依赖关系.此外,使 ...

  9. [转]使用依赖关系注入在 ASP.NET Core 中编写干净代码

    本文转自:http://blog.jobbole.com/101270/ 原文出处: Steve Smith    ASP.NET Core 1.0 是 ASP.NET 的完全重新编写,这个新框架的主 ...

  10. ASP.NET Core 1.0开发Web API程序

    .NET Core版本:1.0.0-rc2Visual Studio版本:Microsoft Visual Studio Community 2015 Update 2开发及运行平台:Windows ...

随机推荐

  1. RocketMQ原理—2.源码设计简单分析上

    大纲 1.NameServer的启动脚本 2.NameServer启动时会解析哪些配置 3.NameServer如何初始化Netty网络服务器 4.NameServer如何启动Netty网络服务器 5 ...

  2. Golang sync.pool源码解析

    Golang sync.pool源码解析 - sync.pool - 是什么 - 怎么用 - demo - 真实世界的使用 - 源码解读-数据结构 - 源码解读-读写流程 - 写流程 - 读流程 - ...

  3. UNIDAC中TDataSet组件CachedUpdates属性使用

    官方方法组合示例,使用UpdatesPending属性可判断是否有修改在缓存区中

  4. react中类似vue的插槽this.props.children的用法

    父组件 <TestHanderClick bg="blue"> <p> 如果我要显示的话,父组件是双标签,子组件中有this.props.children& ...

  5. Django项目实战:从安装到启动服务

    Django项目实战:从安装到启动服务 安装Django 首先,确保你已经安装了 Python 和 pip.然后,使用以下命令来安装 Django : pip install django 安装成功后 ...

  6. [车联网/计算机网络] Autosar 的 `ARXML` 配置数据库文件协议

    序: 缘起 ARXML 概述 : Autosar 的 ARXML 配置数据库文件协议 ARXML 文件 ARXML文件: AUTOSAR系统描述文件,后缀*.arxml 实质是一个XML文件,一般通过 ...

  7. HTML骨架简述

    <!DOCTYPE html><!-- <!声明 DOC docment文件/文档 TYPE 类别/类型 告知浏览器当前文档为html> --><html&g ...

  8. 使用VS Code开发微信小程序

    .MathJax, .MathJax_Message, .MathJax_Preview { display: none } 使用VS Code开发微信小程序 微信开发工具 结构 缺点 VS Code ...

  9. 【ABAQUS2023-Output Vars】使用记录

    计算结构的应变能,ALLSE=所有单元的ESEDEN*EVOL.但这不适用于模态分析,因为模态分析EVOL不能用 ALLSE Field: no History: yes .fil: automati ...

  10. grpc unable to determine Go import path for

    前言 在 proto 文件夹下执行如下命令: $ protoc --go_out=plugins=grpc:. *.proto 报错:无法确定Go导入路径 protoc-gen-go: unable ...