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

embedded/2025/2/8 14:23:11/

目录

配置系统集成

分层项目使用

筛选器的使用

中间件的使用


配置系统集成

在.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/embedded/160554.html

相关文章

JMeter通过BeanShell创建CSV文件

在JMeter中通过BeanShell创建CSV文件&#xff0c;可以使用以下脚本实现&#xff1a; import java.io.FileWriter; import java.io.IOException;// 定义CSV文件路径&#xff08;建议使用绝对路径&#xff09; String csvFilePath "C:/jmeter_test/data/output.csv";…

IEEE 802.3/802.2 | LLC / SNAP

注&#xff1a;本文为 “IEEE 802.3/802.2 | LLC / SNAP” 相关文章合辑。 未整理去重。 第三篇部分内容出自第二篇。 802.2 协议 haoay321 2010-01-28 20:52:02 LLC 协议 LLC&#xff08;Logic Link Control&#xff0c;逻辑链路控制&#xff09;是 IEEE 802.2 协议中规定…

多方法实现影像组学特征降维与选择

大家好&#xff0c;我是带我去滑雪&#xff01; 在机器学习模型中&#xff0c;图像组学特征可分为三类。第一类是相关特征&#xff0c;这些特征对机器学习有积极作用&#xff0c;能够提升学习算法的性能。第二类是无关特征&#xff0c;它们对算法没有任何帮助&#xff0c;不会改…

51单片机(STC89C52)开发:点亮一个小灯

软件安装&#xff1a; 安装开发板CH340驱动。 安装KEILC51开发软件&#xff1a;C51V901.exe。 下载软件&#xff1a;PZ-ISP.exe 创建项目&#xff1a; 新建main.c 将main.c加入至项目中&#xff1a; main.c:点亮一个小灯 #include "reg52.h"sbit LED1P2^0; //P2的…

分布式kettle调度平台- web版转换,作业编排新功能介绍

介绍 Kettle&#xff08;也称为Pentaho Data Integration&#xff09;是一款开源的ETL&#xff08;Extract, Transform, Load&#xff09;工具&#xff0c;由Pentaho&#xff08;现为Hitachi Vantara&#xff09;开发和维护。它提供了一套强大的数据集成和转换功能&#xff0c…

【centOS】搭建公司内网git环境-GitLab 社区版(GitLab CE)

1. 安装必要的依赖 以 CentOS 7 系统为例&#xff0c;安装必要的依赖包&#xff1a; sudo yum install -y curl policycoreutils openssh-server openssh-clients postfix sudo systemctl start postfix sudo systemctl enable postfix2. 添加 GitLab 仓库 curl -sS https:/…

AI驱动测试(三) Dify创建Agent及workflow工作流

Agent介绍 在AI领域&#xff0c;Agent&#xff08;智能体&#xff09;是指一个能够感知环境、进行决策并执行动作的实体。Agent可以是软件程序、机器人或其他形式的智能系统。它通过传感器感知环境&#xff0c;通过执行器对环境产生影响&#xff0c;并通过内部的计算和决策机制…

游戏引擎学习第87天

当直接使用内存时&#xff0c;可能会发生一些奇怪的事情 在直接操作内存时&#xff0c;一些意外的情况可能会发生。由于内存实际上只是一个大块的空间&#xff0c;开发者可以完全控制它&#xff0c;而不像高级语言那样必须遵守许多规则&#xff0c;因此很容易发生错误。在一个…