全栈开发:使用.NET Core WebAPI构建前后端分离的核心技巧(二)

目录

配置系统集成

分层项目使用

筛选器的使用

中间件的使用


配置系统集成

在.net core WebAPI前后端分离开发中,配置系统的设计和集成是至关重要的一部分,尤其是在管理不同环境下的配置数据时,配置系统需要能够灵活、可扩展,且易于维护。下面是配置系统集成的一些实现方式:

1)加载现有的IConfiguration

2)加载项目根目录下的appsettings.json

3)加载项目根目录下的appsettings.{Environment}.json

4)当程序运行在开发环境下,程序会加载“用户机密"配置

5)加载环境变量中的配置

6)加载命令行中的配置

在运行环境中.net core会从环境变量中读取名字为ASPNETCORE_ENVIRONMENT的值,其中推荐值:Development(开发环境)、Staging(测试环境)、Production(生产环境),其中读取的方法就是类似app.Environment.EnvironmentName、app.Environment.IsDevelopment()等,例如:

如下在入口文件中,设置了只有在开发环境下才有swagger,正式环境直接调用接口即可

在Windows和VS(推荐开发环境)中设置环境变量,可以采用如下的方法进行,右键项目打开属性,找到调试打开常规中的环境变量进行设置即可:

机密文件存放:在网上有很多新闻报道了由于公司程序员的失误操作将公司的机密数据如账户密码上传到github上去导致信息泄露,为了防止该事件的发生我们可以将不方便放到appsettings.json中的机密信息放到一个不在项目中的json文件中。

在asp.net core项目上单击鼠标右键,选择管理用户机密,在secrets.json文件中输入我们的机密信息,如下所示:

然后我们鼠标右键该文件打开文件所在目录,可以看到该文本并不在我们的项目中而是在C盘的某个文件目录下面,其中文件目录下UserSecrets后面的一串字符,就是csproj文件中的<UserSecretId>的数据,项目运行的时候也是第一时间识别该数据:

该secrets.json文件也不需要我们进行特殊读取,.net core会默认直接把它添加到我们的配置系统当中去,我们直接在入口文件通过Configuration就可以直接读取了,如下所示:

string str = app.Configuration.GetSection("conStr").Value;
Console.WriteLine(str);

注意:该方法供开发人员使用的,不适合在生产环境中使用。并且该方法仍然是明文存储,如果不想别人看到则需要采用Azure KeyVault等方法,并且无法完全避免,最重要的还是要加强安全防控意识。如果因为重装、新员工等原因导致secrets.json重建,就要重新配置,十分的麻烦,如果影响大的话还是用集中式配置服务器。

分层项目使用

在.net core webapi项目中进行项目分层是为了提高代码的可维护性、可扩展性和可测试性,通过分层设计可以将不同的关注点隔离开来,简化代码结构,使得每个层级的职责清晰,从而提高开发效率和代码质量。常见的分层方式包括:表示层、业务逻辑层、数据访问层。

例如:创建一个.net类库项目EFCoreBooks,放实体类和配置类等,在该项目下按照如下包,这里推荐都按照8版本,比较稳定,高版本可能出现版本冲突报错:

然后就是在该EFCoreBooks类库当中创建实体类和配置类,然后再创建DbContext,如下:

namespace EFCoreBooks
{public class MyDbContext:DbContext{public DbSet<Book> Books { get; set; }public MyDbContext(DbContextOptions<MyDbContext> options) : base(options){}protected override void OnConfiguring(DbContextOptionsBuilder options){base.OnConfiguring(options);}protected override void OnModelCreating(ModelBuilder model){base.OnModelCreating(model);model.ApplyConfigurationsFromAssembly(this.GetType().Assembly); // 配置当前程序集下的所有配置类}}
}

设置这里我们需要设置一下有入口文件的webapi_study项目为启动项目,然后切换到我们设置实体类的项目中,执行如下命令进行数据库的迁移:

最终可以看到我们设置的实体类数据已经成功迁移到数据库当中,如下所示:

然后我们在入口文件中配置DbContext连接数据库,这里的连接文件数据使用secrets.json文件:

然后我们在控制器当中注入DbContext,然后获取数据库当中Books中的数量:

然后这里我们手动在数据库当中添加一条数据之后,发起请求打印了当前表的数量是1,没问题:

筛选器的使用

在.net core webapi中筛选器(Filters)是用于处理请求和响应的机制,可以帮助在请求处理管道中插入自定义逻辑,筛选器可用于在控制器方法执行之前或之后执行特定的代码,比如验证、日志记录、异常处理、授权等,在.net core webapi中筛选器有几种类型主要包括以下几种:

1)授权筛选器(Authorization Filters)

2)资源筛选器(Resource Filters)

3)模型绑定筛选器(Model Binding Filters)

4)操作筛选器(Action Filters)

5)异常筛选器(Exception Filters)

6)结果筛选器(Result Filters)

所有筛选器一般有同步和异步两个版本,比如IActionFilter、IAsyncActionFilter接口,接下来重点讲解Exception filter和Actionfilter这两个筛选器:如下所示:

操作筛选器:Actionfilter,在控制器方法执行之前和之后执行,可以对请求进行预处理或对响应进行后处理,多个ActionFilter是链式执行的,如下图所示:

如下我们定义一个捕获处理步骤的类:

namespace webapi_study
{public class MyActionFilter: IAsyncActionFilter{public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){Console.WriteLine("MyActionFilter 开始执行");ActionExecutedContext result = await next();if (result.Exception != null){Console.WriteLine("MyActionFilter 捕获异常");}else{Console.WriteLine("MyActionFilter 执行完毕");}}}
}

然后我们把其注册到入口文件当中去:

builder.Services.Configure<MvcOptions>(options =>
{options.Filters.Add<MyActionFilter>();
});

然后我们在接口中进行调用接口,第一个接口是正常的,执行了开始到结束,第二个接口是异常的,执行了开始到捕获异常,如下所示:

案例:为了避免恶意客户端频繁发送大量请求消耗服务器资源,我们要实现“一秒钟内只允许最多有一个来自同一个IP地址的请求”,在Action Filter中,如果我们不调用await next(),就可以终止Action方法的执行了,如下我们创建限制IP请求的类:

namespace webapi_study
{public class RateLimitActionFilter: IAsyncActionFilter{private readonly IMemoryCache memCache;public RateLimitActionFilter(IMemoryCache memCache){this.memCache = memCache;}public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next){string ip = context.HttpContext.Connection.RemoteIpAddress.ToString();string cacheKey = $"ip_{ip}";long? lastVisit = memCache.Get<long?>(cacheKey);if (lastVisit ==null || Environment.TickCount64 - lastVisit > 1000){memCache.Set(cacheKey, Environment.TickCount64, TimeSpan.FromSeconds(10)); // 避免长期不访问的IP占用缓存await next();}else{ObjectResult result = new ObjectResult("访问过于频繁,请稍后再试") {StatusCode = 429};context.Result = result;}}}
}

异常筛选器:Exception Filters,在控制器方法抛出异常时执行,通常用于处理未处理的异常

如下我们定义一个捕获异常信息时候,返回设置内容的类:

namespace webapi_study
{public class MyExceptionFilter: IAsyncExceptionFilter{private readonly IWebHostEnvironment hostEnv;public MyExceptionFilter(IWebHostEnvironment hostEnv){this.hostEnv = hostEnv;}public Task OnExceptionAsync(ExceptionContext context){// context.Exception 代表捕获到的异常信息对象// context.ExceptionHandled = true; 表示捕获到异常后不再向上抛出// context.Result 其值会被输出到客户端string msg;if (hostEnv.IsDevelopment()){msg = context.Exception.ToString();}else{msg = "服务器内部错误";}ObjectResult result = new ObjectResult(new { code = 500, message=msg });context.Result = result; // 输出到客户端的内容context.ExceptionHandled = true; // 捕获到异常后不再向上抛出context.Result = result; // 输出到客户端的内容return Task.CompletedTask; // 异步方法返回结果}}
}

当然也可以设置一个日志记录的类,当捕获到异常之后将异常信息写入的文件当中:

namespace webapi_study
{public class LogExceptionFilter: IAsyncExceptionFilter{public Task OnExceptionAsync(ExceptionContext context){return File.AppendAllTextAsync("d:/error.log", context.Exception.ToString());}}
}

然后我们在入口文件当中将这个两个异常捕获的类注入到服务当中:

builder.Services.Configure<MvcOptions>(options =>
{options.Filters.Add<MyExceptionFilter>();options.Filters.Add<LogExceptionFilter>();
});

然后我们设置一个接口,访问一个根本不存在的文件:

[HttpGet]
public string Test()
{string s = System.IO.File.ReadAllText("d:/123123123.txt");return s;
}

打印的效果如下所示,当前的code为500,文件显示不存在:

中间件的使用

中间件(Middleware):是请求处理管道中的一个重要概念,中间件是一个组件它在处理HTTP请求时拦截请求、响应,或者在请求和响应之间执行一些逻辑操作,它可以对请求进行预处理、对响应进行后处理,或在请求处理过程中添加自定义功能,如下图所示:

中间件由前逻辑、next、后逻辑3部分组成,前逻辑为第一段要执行的逻辑代码、next为指向下一个中间件的调用、后逻辑为从下一个中间件执行返回所执行的逻辑代码,每个HTTP请求都要经历一系列中间件的处理,每个中间件对于请求进行特定的处理后,再转到下一个中间件,最终的业务逻辑代码执行完成后,响应的内容也会按照处理的相反顺序进行处理,然后形成HTTP响应报文返回给客户端。

从广义上来讲Tomcat、WebLogic、Redis、lIS都是中间件,狭义上来讲ASP.NET Core中的中间件指ASP.NET Core中的一个组件。中间件组成一个管道,整个ASP.NETCore的执行过程就是HTTP请求和响应按照中间件组装的顺序在中间件之间流转的过程。开发人员可以对组成管道的中间件按照需要进行自由组合,中间件主要有以下三个概念:

1)Map:用来定义一个管道可以处理哪些请求

2)Use:每个Use引入一个中间件

3)Run:是用来执行最终的核心应用逻辑

其实这个中间件手写的话,就类似前端node中的express框架,如下我们在入口文件简单写个中间件:

using Microsoft.AspNetCore.Builder;var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();//app.MapGet("/test", () => "Hello World!");
app.Map("/test", static async (pipeBuilder) => {pipeBuilder.Use(async (context, next) => {context.Response.ContentType = "text/html";await context.Response.WriteAsync("1 start<br />");await next.Invoke();await context.Response.WriteAsync("1 end<br />");});pipeBuilder.Use(async (context, next) => {await context.Response.WriteAsync("2 start<br />");await next.Invoke();await context.Response.WriteAsync("2 end<br />");});pipeBuilder.Run(async context =>{await context.Response.WriteAsync("Run<br />");});
});
app.Run();

运行项目得到的结果如下所示:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/67957.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

上海路网道路 水系铁路绿色住宅地工业用地面图层shp格式arcgis无偏移坐标2023年

标题和描述中提到的资源是关于2023年上海市地理信息数据的集合&#xff0c;主要包含道路、水系、铁路、绿色住宅区以及工业用地的图层数据&#xff0c;这些数据以Shapefile&#xff08;shp&#xff09;格式存储&#xff0c;并且是适用于ArcGIS软件的无偏移坐标系统。这个压缩包…

Rust HashMap :当储物袋遇上物品清单

开场白&#xff1a;哈希映射的魔法本质 在Rust的奇幻世界里&#xff0c;HashMap就像魔法师的储物袋&#xff1a; 键值对存储 → 每个物品都有专属咒语&#xff08;键&#xff09;和实体&#xff08;值&#xff09;快速查找 → 念咒瞬间召唤物品动态扩容 → 自动伸展的魔法空间…

Spring Boot统一异常拦截实践指南

Spring Boot统一异常拦截实践指南 一、为什么需要统一异常处理 在Web应用开发中&#xff0c;异常处理是保证系统健壮性和用户体验的重要环节。传统开发模式中常见的痛点包括&#xff1a; 异常处理逻辑分散在各个Controller中错误响应格式不统一敏感异常信息直接暴露给客户端…

使用 Elastic Cloud Hosted 优化长期数据保留:确保政府合规性和效率

作者&#xff1a;来自 Elastic Jennie Davidowitz 在数字时代&#xff0c;州和地方政府越来越多地承担着管理大量数据的任务&#xff0c;同时确保遵守严格的监管要求。这些法规可能因司法管辖区而异&#xff0c;通常要求将数据保留较长时间 —— 有时从一年到七年不等。遵守刑事…

Oracle Primavera P6 最新版 v24.12 更新 2/2

目录 一. 引言 二. P6 EPPM 更新内容 1. 用户管理改进 2. 更轻松地标准化用户设置 3. 摘要栏标签汇总数据字段 4. 将里程碑和剩余最早开始日期拖到甘特图上 5. 轻松访问审计数据 6. 粘贴数据时排除安全代码 7. 改进了状态更新卡片视图中的筛选功能 8. 直接从活动电子…

linux本地部署deepseek-R1模型

国产开源大模型追平甚至超越了CloseAI的o1模型&#xff0c;大国崛起时刻&#xff01;&#xff01;&#xff01; DeepSeek R1 本地部署指南   在人工智能技术飞速发展的今天&#xff0c;本地部署AI模型成为越来越多开发者和企业关注的焦点。本文将详细介绍如何在本地部署DeepS…

C基础寒假练习(2)

一、输出3-100以内的完美数&#xff0c;(完美数&#xff1a;因子和(因子不包含自身)数本身 #include <stdio.h>// 函数声明 int isPerfectNumber(int num);int main() {printf("3-100以内的完美数有:\n");for (int i 3; i < 100; i){if (isPerfectNumber…

有限元分析学习——Anasys Workbanch第一阶段笔记梳理

第一阶段笔记主要源自于哔哩哔哩《ANSYS-workbench 有限元分析应用基础教程》 张晔 主要内容导图&#xff1a; 笔记导航如下&#xff1a; Anasys Workbanch第一阶段笔记(1)基本信息与结果解读_有限元分析变形比例-CSDN博客 Anasys Workbanch第一阶段笔记(2)网格单元与应力奇…

html基本结构和常见元素

html5文档基本结构 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><title>文档标题</title> </head> <body>文档正文部分 </body> </html> html文档可分为文档头和文档体…

Cursor如何使用Google Gemini以及碰到的坑

Cursor如何使用Google Gemini以及碰到的坑 Cursor介绍下载安装Google Gemini介绍Google Gemini 官网申请Google Gemini API网址 配置Cursor使用Google Gemini打开Corsur设置 Cursor介绍 ‌Cursor是一款基于人工智能的代码编辑器&#xff0c;旨在帮助开发者更高效地编写代码。‌…

【云安全】云原生-K8S-简介

K8S简介 Kubernetes&#xff08;简称K8S&#xff09;是一种开源的容器编排平台&#xff0c;用于管理容器化应用的部署、扩展和运维。它由Google于2014年开源并交给CNCF&#xff08;Cloud Native Computing Foundation&#xff09;维护。K8S通过提供自动化、灵活的功能&#xf…

【C++】线程池实现

目录 一、线程池简介线程池的核心组件实现步骤 二、C11实现线程池源码 三、线程池源码解析1. 成员变量2. 构造函数2.1 线程初始化2.2 工作线程逻辑 3. 任务提交(enqueue方法)3.1 方法签名3.2 任务封装3.3 任务入队 4. 析构函数4.1 停机控制 5. 关键技术点解析5.1 完美转发实现5…

深入理解 C# 与.NET 框架

.NET学习资料 .NET学习资料 .NET学习资料 一、引言 在现代软件开发领域&#xff0c;C# 与.NET 框架是构建 Windows、Web、移动及云应用的强大工具。C# 作为一种面向对象的编程语言&#xff0c;而.NET 框架则是一个综合性的开发平台&#xff0c;它们紧密结合&#xff0c;为开…

雷电等基于VirtualBox的Android模拟器映射串口和测试CSerialPort串口功能

雷电等基于VirtualBox的Android模拟器映射串口和测试CSerialPort串口功能 1. 修改VirtualBox配置文件映射串口 模拟器配置文件vms/leidian0/leidian.vbox。 在UART标签下增加(修改完成后需要将leidian.vbox修改为只读) <Port slot"1" enabled"true"…

【Linux系统】SIGCHLD 信号(选学了解)

SIGCHLD 信号 使用wait和waitpid函数可以有效地清理僵尸进程。父进程可以选择阻塞等待&#xff0c;直到子进程结束&#xff1b;或者采用非阻塞的方式&#xff0c;通过轮询检查是否有子进程需要被回收。 然而&#xff0c;无论是选择阻塞等待还是非阻塞的轮询方式&#xff0c;父…

【R语言】获取数据

R语言自带2种数据存储格式&#xff1a;*.RData和*.rds。 这两者的区别是&#xff1a;前者既可以存储数据&#xff0c;也可以存储当前工作空间中的所有变量&#xff0c;属于非标准化存储&#xff1b;后者仅用于存储单个R对象&#xff0c;且存储时可以创建标准化档案&#xff0c…

Vim的基础命令

移动光标 H(左) J(上) K(下) L(右) $ 表示移动到光标所在行的行尾&#xff0c; ^ 表示移动到光标所在行的行首的第一个非空白字符。 0 表示移动到光标所在行的行首。 W 光标向前跳转一个单词 w光标向前跳转一个单词 B光标向后跳转一个单词 b光标向后跳转一个单词 G 移动光标到…

11. 9 构建生产级聊天对话记忆系统:从架构设计到性能优化的全链路指南

构建生产级聊天对话记忆系统:从架构设计到性能优化的全链路指南 关键词: 聊天对话记忆系统、多用户会话管理、LangChain生产部署、Redis记忆存储、高并发对话系统 一、服务级聊天记忆系统核心需求 多用户隔离:支持同时处理数千个独立对话持久化存储:对话历史不因服务重启丢…

Block Blaster Online:免费解谜游戏的乐趣

Block Blaster Online 是一款免费的在线解谜游戏&#xff0c;它将挑战你的思维和反应能力&#xff01;在这里&#xff0c;你可以匹配五彩缤纷的方块&#xff0c;创造出令人惊叹的组合&#xff0c;享受无尽的解谜乐趣。无需安装&#xff0c;点击即可开始&#xff0c;加入全球数百…

Guided Decoding (借助FSM,有限状态自动机)

VLLM对结构化输出的支持&#xff1a; vllm/docs/source/features/structured_outputs.md at main vllm-project/vllm GitHub VLLM对tool call的支持&#xff1a; vllm/docs/source/features/tool_calling.md at main vllm-project/vllm GitHub 以上指定输出格式&#xf…