全栈开发:使用.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.rhkb.cn/news/12628.html

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

相关文章

Linux——进程概念

目录 一、系统调用和库函数概念二、基本概念三、描述进程-PCB3.1 task_struct-PCB的一种3.2 task_ struct内容分类 四、组织进程五、查看进程六、通过系统调用获取进程标示符七、通过系统调用创建进程- fork初始7.1 fork函数创建子进程7.2 fork 之后通常要用 if 进行分流 八、进…

基于Springboot框架的学术期刊遴选服务-项目演示

项目介绍 本课程演示的是一款 基于Javaweb的水果超市管理系统&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该项目附…

2. K8S集群架构及主机准备

本次集群部署主机分布K8S集群主机配置主机静态IP设置主机名解析ipvs管理工具安装及模块加载主机系统升级主机间免密登录配置主机基础配置完后最好做个快照备份 2台负载均衡器 Haproxy高可用keepalived3台k8s master节点5台工作节点(至少2及以上)本次集群部署主机分布 K8S集群主…

Linux第105步_基于SiI9022A芯片的RGB转HDMI实验

SiI9022A是一款HDMI传输芯片&#xff0c;可以将“音视频接口”转换为HDMI或者DVI格式&#xff0c;是一个视频转换芯片。本实验基于linux的驱动程序设计。 SiI9022A支持输入视频格式有&#xff1a;xvYCC、BTA-T1004、ITU-R.656&#xff0c;内置DE发生器&#xff0c;支持SYNC格式…

物联网领域的MQTT协议,优势和应用场景

MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;作为轻量级发布/订阅协议&#xff0c;凭借其低带宽消耗、低功耗与高扩展性&#xff0c;已成为物联网通信的事实标准。其核心优势包括&#xff1a;基于TCP/IP的异步通信机制、支持QoS&#xff08;服务质量&…

Baklib推动数字化内容管理解决方案助力企业数字化转型

内容概要 在当今信息爆炸的时代&#xff0c;数字化内容管理成为企业提升效率和竞争力的关键。企业在面对大量数据时&#xff0c;如何高效地存储、分类与检索信息&#xff0c;直接关系到其经营的成败。数字化内容管理不仅限于简单的文档存储&#xff0c;更是整合了文档、图像、…

PAT甲级1052、Linked LIst Sorting

题目 A linked list consists of a series of structures, which are not necessarily adjacent in memory. We assume that each structure contains an integer key and a Next pointer to the next structure. Now given a linked list, you are supposed to sort the stru…

18 大量数据的异步查询方案

在分布式的应用中分库分表大家都已经熟知了。如果我们的程序中需要做一个模糊查询&#xff0c;那就涉及到跨库搜索的情况&#xff0c;这个时候需要看中间件能不能支持跨库求交集的功能。比如mycat就不支持跨库查询&#xff0c;当然现在mycat也渐渐被摒弃了(没有处理笛卡尔交集的…

UE求职Demo开发日志#21 背包-仓库-装备栏移动物品

1 创建一个枚举记录来源位置 UENUM(BlueprintType) enum class EMyItemLocation : uint8 {None0,Bag UMETA(DisplayName "Bag"),Armed UMETA(DisplayName "Armed"),WareHouse UMETA(DisplayName "WareHouse"), }; 2 创建一个BagPad和WarePa…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.22 形状操控者:转置与轴交换的奥秘

1.22 形状操控者&#xff1a;转置与轴交换的奥秘 目录 #mermaid-svg-Qb3eoIWrPbPGRVAf {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Qb3eoIWrPbPGRVAf .error-icon{fill:#552222;}#mermaid-svg-Qb3eoIWrPbPGRVAf…

Redis - String相关命令

目录 setgetmsetmgetsetnx、setex、psetexincr、incrby、decr、decrby、incrbyfloatappendgetrangesetrangestrlen字符串类型编码方式总结 Redis - String Redis存储的字符串&#xff0c;是直接按二进制方式存储&#xff0c;不会做任何编码转换&#xff0c;存的是什么&#xff…

html基本结构和常见元素

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

LabVIEW的智能电源远程监控系统开发

在工业自动化与测试领域&#xff0c;电源设备的精准控制与远程管理是保障系统稳定运行的核心需求。传统电源管理依赖本地手动操作&#xff0c;存在响应滞后、参数调节效率低、无法实时监控等问题。通过集成工业物联网&#xff08;IIoT&#xff09;技术&#xff0c;实现电源设备…

33.Word:国家中长期人才发展规划纲要【33】

目录 NO1.2样式​ NO3​ 图表 ​ NO4.5.6​ 开始→段落标记视图→导航窗格→检查有无遗漏 NO1.2样式 F12/另存为&#xff1a;Word.docx&#xff1a;考生文件夹样式的复制样式的修改 样式的应用&#xff08;没有相似/超级多的情况下&#xff09;——替换 [ ]通配符&#x…

图漾相机——Sample_V1示例程序

文章目录 1.SDK支持的平台类型1.1 Windows 平台1.2 Linux平台 2.SDK基本知识2.1 SDK目录结构2.2 设备组件简介2.3 设备组件属性2.4 设备的帧数据管理机制2.5 SDK中的坐标系变换 3.Sample_V1示例程序3.1 DeviceStorage3.2 DumpCalibInfo3.3 NetStatistic3.4 SimpleView_SaveLoad…

Java集合框架

欢迎并且感谢大家指出我的问题&#xff0c;由于本人水平有限&#xff0c;有些内容写的不是很全面&#xff0c;只是把比较实用的东西给写下来&#xff0c;如果有写的不对的地方&#xff0c;还希望各路大牛多多指教&#xff01;谢谢大家&#xff01;&#x1f970; 一、引言 在 Ja…

DeepSeek最新图像模型Janus-Pro论文阅读

目录 论文总结 摘要 1. 引言 2. 方法 2.1 架构 2.2 优化的训练策略 2.4 模型扩展 3. 实验 3.1 实施细节 3.2 评估设置 3.3 与最新技术的比较 3.4 定性结果 4. 结论 论文总结 Janus-Pro是DeepSeek最新开源的图像理解生成模型&#xff0c;Janus-Pro在多模态理解和文…

Python爬虫:1药城店铺爬虫(完整代码)

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

【蓝桥杯】日志统计

日志统计&#xff08;编程题&#xff09;https://dashoj.com/d/lqbproblem/p/53https://dashoj.com/d/lqbproblem/p/53https://dashoj.com/d/lqbproblem/p/53 题目 日志统计(编程题) 讲解 这个讲解感觉比较通俗易懂。 蓝桥杯2018年省赛B组08&#xff08;c/c&#xff09;日…

一文讲解Spring中应用的设计模式

我们都知道Spring 框架中用了蛮多设计模式的&#xff1a; 工厂模式呢&#xff0c;就是用来创建对象的&#xff0c;把对象的创建和使用分开&#xff0c;这样代码更灵活。代理模式呢&#xff0c;是用一个代理对象来控制对真实对象的访问&#xff0c;可以在访问前后做一些处理。单…