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

news/2025/2/8 0:01:36/

目录

配置系统集成

分层项目使用

筛选器的使用

中间件的使用


配置系统集成

在.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.ppmy.cn/news/1570179.html

相关文章

2025简约的打赏系统PHP网站源码

源码介绍 2025简约的打赏系统PHP网站源码 源码上传服务器&#xff0c;访问域名/install.php安装 支持自定义金额打赏 集成支付宝当面付 后台管理系统 订单记录查询 效果预览 源码获取 2025简约的打赏系统PHP网站源码

《Python预训练视觉和大语言模型》:从DeepSeek到大模型实战的全栈指南

就是当代AI工程师的日常&#xff1a;* - 砸钱买算力&#xff0c;却卡在分布式训练的“隐形坑”里&#xff1b; - 跟着论文复现模型&#xff0c;结果连1/10的性能都达不到&#xff1b; - 好不容易上线应用&#xff0c;却因伦理问题被用户投诉…… 当所有人都在教你怎么调用…

解锁豆瓣高清海报(二) 使用 OpenCV 拼接和压缩

解锁豆瓣高清海报(二): 使用 OpenCV 拼接和压缩 脚本地址: 项目地址: Gazer PixelWeaver.py pixel_squeezer_cv2.py 前瞻 继上一篇“解锁豆瓣高清海报(一) 深度爬虫与requests进阶之路”成功爬取豆瓣电影海报之后&#xff0c;本文将介绍如何使用 OpenCV 对这些海报进行智…

10.4 LangChain核心架构揭秘:模块化设计如何重塑大模型应用开发?

LangChain核心架构揭秘:模块化设计如何重塑大模型应用开发? 关键词: LangChain模块化设计、大模型开发框架、LangChain核心概念、AI应用开发、LLM工程化 一、LangChain的模块化设计哲学:从“手工作坊”到“工业化生产” 传统开发痛点: 代码重复:每个项目从零开始编写胶…

Vuex 解析:从 Vue 2 到 Vue 3 的演变与最佳实践

Vuex 是 Vue.js 中的状态管理模式&#xff0c;广泛应用于 Vue 2 和 Vue 3 中&#xff0c;其内部实现存在一些差异。 1. 什么是 Vuex &#xff1f; Vuex 是 Vue.js 官方提供的状态管理库&#xff0c;用于集中管理应用的所有组件的状态。主要是通过一种集中化的方式来管理共享状…

kubernetes 核心技术-集群安全机制 RBAC

随着 Kubernetes 在企业级应用中的广泛采用&#xff0c;确保集群的安全性变得至关重要。Kubernetes 提供了多种安全机制来保护集群及其资源免受未授权访问和潜在威胁的影响。其中&#xff0c;基于角色的访问控制&#xff08;Role-Based Access Control, 简称 RBAC&#xff09;是…

使用 postman 测试思源笔记接口

思源笔记 API 权鉴 官方文档-中文&#xff1a;https://github.com/siyuan-note/siyuan/blob/master/API_zh_CN.md 权鉴相关介绍截图&#xff1a; 对应的xxx&#xff0c;在软件中查看 如上图&#xff1a;在每次发送 API 请求时&#xff0c;需要在 Header 中添加 以下键值对&a…

node.js 08 express的使用和热重载nodemon的安装

一.express的安装和使用 安装 npm i express 使用 //引入express const express require(express)//启动服务器 const app express()//设置get请求地址&#xff0c;获取请求地址信息&#xff0c;和发送返回的数据 app.get(/bailan,(req, res) > {//req.query可以获取到客…