首页 > 编程语言 >在 ASP.NET Core 中编写高性能 Web API 的4个小技巧

在 ASP.NET Core 中编写高性能 Web API 的4个小技巧

时间:2024-10-10 09:24:31浏览次数:9  
标签:Web ASP logs await 缓存 Task API async logErrors

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);
}

两端代码看起来非常相似,最大的区别在于缓存存储的位置。

标签:Web,ASP,logs,await,缓存,Task,API,async,logErrors
From: https://www.cnblogs.com/denglei1024/p/18455608

相关文章

  • springboot+vue基于javaweb电费管理系统【开题+程序+论文】
    系统程序文件列表开题报告内容研究背景随着信息化技术的飞速发展,各行各业的管理效率与服务质量均得到了显著提升。在电力行业中,电费管理作为其核心业务流程之一,直接关系到电力企业的运营效益与用户的满意度。传统的电费管理方式大多依赖于人工操作,不仅耗时费力,还容易出错,难......
  • asp.net c#获取内部网关地址
    在ASP.NET中获取内部网关地址,可以使用NetworkInterface类来获取所有网络接口的信息,然后找到默认网关的IP地址。以下是一个示例代码:usingSystem;usingSystem.Net;usingSystem.Net.NetworkInformation;publicclassProgram{publicstaticvoidMain(){......
  • 为知笔记API文档
    为知笔记API快速上手主要架构为知笔记服务主要分为两部分:账号服务数据服务其中账号服务(as:AccountServer)只有一个服务地址,主要提供账号相关的服务,例如登录,注销,获取用户信息,获取用户数据信息等。一个账号可以有一个或者多个知识库(kb:KnowledgeBase),每一个kb都是独立的。......
  • SpringBootWeb AOP
    SpringBootWebAOP事务管理rollbackFor属性propagation属性 案例AOP基础 进阶通知类型通知顺序 切入点表达式execution@annotation连接点案例实体类接口方法切面类事务管理rollbackFor属性propagation属性REQUIRED:大部分情况下都是用该传播行......
  • 一个适用于 ASP.NET Core 的轻量级插件框架
    前言今天大姚给大家分享一个适用于ASP.NETCore的轻量级插件框架,简单配置,开箱即用:PluginCore。项目概述PluginCore是一个基于ASP.NETCore的轻量级插件框架,旨在简化插件的集成与管理。通过最少的配置,开发者可以快速集成并专注于业务逻辑的开发。它支持动态WebAPI、插件隔......
  • 【Web自动化测试】Python + Selenium实现携程网火车票订购的自动化测试——PO模式篇
    目录1.PO模式2.目录结构3.代码(1).base层——`base.py`(2).common层——`function.py`(3).data层——`data.yaml`(4).po层——`login_page.py`(5).po层——`search_trains_page.py`(6).po层——`filter_tickets_page.py`(7).po层——`order_page.py`(8).testcase层——`test_b......
  • (开题)flask框架基于Web的立直麻将业余运动员考级管理系统(程序+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着互联网技术的飞速发展,电子商务已成为现代商业的重要组成部分。礼品卡作为一种新型的礼品形式,因其便捷性、灵活性和个性化特点,受到了广......
  • 树莓派 RasperryPi 开源免费的PLC通讯神器 LECPython,和欧姆龙Omron PLC通讯示例
    简介LECPython是一个强大的Python组件,基于C#开发,能够实现Python与PLC之间的高效通信。本文将指导您如何在树莓派(RaspberryPi)上安装和使用LECPython组件,为您的工业自动化项目提供便利。LECPython旨在解决在树莓派等嵌入式设备上,与可编程逻辑控制器(PLC)建立高效通信的......
  • 解密网易云音乐Web端的请求参数params与encSecKey
    网易云音乐作为一款功能强大的音乐流媒体平台,为用户提供了丰富的音乐体验和社区互动。然而,当用户希望批量下载音乐资源,尤其是整个歌单或某位歌手的全部歌曲时,受限于版权保护和平台策略,官方渠道通常无法直接实现这一需求。在这种情况下,一些技术爱好者或开发者可能会转向使用......
  • web网页制作(Radio Shack)
    <!doctypehtml>BootstrapdemoRadioShackStoreLocatorSteve'sWorkbenchRadioShackServicesElectronicRepairAboutRadioShackProductSupportRockandRollOnTourUnitedAgainstCrime......