【.NETCore 3】Ids4 ║ 统一角色管理(上)

前言

书接上文,咱们在上周,通过一篇《思考》 性质的文章,和很多小伙伴简单的讨论了下,如何统一同步处理角色的问题,众说纷纭,这个我一会儿会在下文详细说到,而且我最终也定稿方案了。所以今天咱们就大刀阔斧的开始迁移之路,这个 IdentityServer4 项目也是要尽快的完结,因为第六个系列《设计模式》已经开始了,然后还有直播,和录制视频,积压太多会得不偿失,而且好像还有人让我讲我的项目,所以,这两周先把我在线的项目迁移了,WPF的项目就留在录制 IdentityServer4 视频里给大家详细讲解,文字教程到时候看看要不要补充一下。

那既然说到了角色管理,可能有一部分读过我文章的小伙伴,脑海中稍微有点儿类似的印象,数据管理?好像之前说过,没错!在上上一篇文章中,我们说到了《用户数据管理》,主要就是用户数据的增删改查,然后添加种子数据,从我的 Github 上自动生成,除了用户,当时也生成了一点 Role 信息,只不过那里的 Role 信息,是固定的,不能修改,而且也仅仅是作为User 的 Claim 声明来做处理的,并没有涉及到真正的 Role 管理,比如基本的CURD ,但是今天我们就正式的开始对角色信息进行统一处理了 ,废话不多说,直接开始。

 

在写这篇文章的时候,是半夜,越写越多,最后发现不得已,无奈的在文章标题里加了个()字,其实文章太长也不好,也不知道我为啥这么话痨????。

 

 

零、今天要实现橙色的部分

 

 

 

 一、Role 的数据同步方案之回顾

 

在刚刚的前言中,我们说到了上一篇文章《五 ║ 多项目集成统一认证中心的思考》里,我们讨论了几种同步 Role 的方案,很是精彩,主要是文章下边的评论很精彩,可能看的多了,一不小心会有一种神仙打架的意味,因此这里我简单的做下总结吧,既是对上篇文章的回顾,也是今天这篇文章的引子,为了看着更清楚,我这里用编号来表示我们的思路:

 

01、我们的 IdentityServer4 项目是一个去中心化的认证服务中心,他提供一个 token 令牌,来实现我们对资源服务器的授权处理;

02、既然要授权,我们就需要对 Token 做一定的处理,这里一般是增加声明 Claim,常见的就是 Role 信息;

03、然后我们从服务中心成功登录后返回,并携带一个含有 Role Claim信息的 Token 令牌;

04、接着在返回到的资源服务器里,对 api 进行自定义授权,来对当前 Token 令牌,也等同于 Token 的持有者进行访问限制;

05、那这个时候问题来了,我们的资源服务器看起来,本应该是不用关心我们的用户信息和角色信息的,是要交给认证中心的;

06、但是 Blog.Core 项目,我们用到了数据库的动态分配授权,是根据 Role 来分配特定的 api/url 的;

07、也就意味着我们要把 Role 放到资源服务器,但是上边第 05 点,我们明确 Role 的管理是在 Identity 项目的;

08、这个时候方案就来了,

09、一:我们可以做一个定时器,定时将 Identity 认证项目的Role同步到资源服务器;

10、二:在 Identity 项目开发一个 api 接口,方便我们在 资源服务器 里调用;

11、三:直接把 Identity 和 core 项目共用一个 db 数据库,使用一个 Role 表,就完美解决这个问题了;

12、四:单独抽离出一个 Role 做分布式服务管理中心,可以使用 Redis,就是把 Role 单独一个微服务,让所有项目使用;

13、:最简单的方法,Identity 项目单独一个 db 库,但是我们的资源服务器手动在 controller 上配置Authorize;

14、等等等等,还有其他的一些思路,不列举。

 

从上边的这一系列大家可以看得出来,我们平时开发还是需要很多的思考的,也是需要多多的讨论,这样才能进步。

最终思考了很久,我还是采用了方案三和方案五,这两个简单的方案,你可能好奇,为啥是两个呢?而且感觉两个背道而驰,一个是合并,一个是分库,怎么能同时使用呢,其实很简单的,因为我有多个资源服务器,这里目前就用两个吧 —— Blog.Core 的前后端分离的 api 项目 和 ChristDDD 的 MVC 项目,当然以后还会有 WPF 项目。

我在 Blog.Core 项目采用方案三,合并到一个数据库,可以很好的解决动态授权问题,

然后在 MVC 项目里,就采用手动在 controller 添加特性的形式吧,也就是方案五,这样就完全满足了需求,

也能够同时给大家展示两种方案,从而达到学习的目的

好啦,到了现在,大家应该也明白了我以后的设计思路和开发方案了,现在就开始动手处理 Role 数据了。

 

 

 

二、两种管理 ROLE 的方案

 

说明:以下内容可能有点儿绕,或者有点儿不容易懂,大家不要慌,我会这两篇详细讲解,而且也会在视频中,详细给大家说明的,但是还是尽量能跟的上。

如果你使用 Ids4 项目的话(这里准确来讲,是开发 Identity 的话,因为两者是不一样的哟),会有两种开发方式.

 

1、简述 Ids4 数据库框架三模块

在我们的 Ids4 项目中,我们在之前的文章中也说到了,一共有三个模块,对应了三个上下文,分别是配置数据ConfigurationDbContext、操作数据PersistedGrantDbContext,然后最后才是用户数据ApplicationDbContext ,前两个是 IdentityServer4 的相关类库,第三个其实不是 Ids4 官方的,而且 NetCore 自带的一个类库,只是帮助我们更好的处理用户数据的。

我们使用前两个上下文来实现 Ids4 的去中心化认证,而第三个 ApplicationDbContext  只是来存储我们的用户和角色数据的。

因此!这个时候我们知道了,其实我们无论怎么处理用户和角色数据,是不会影响 Ids4 整体性操作的,这个时候我们就恍然大悟了,这个时候两种方案就出来了:

 

 2、自定义封装,实现用户角色数据的持久化

这个第一种就是自己封装一个 Repository 仓储的方式,然后搭配 EFCore 持久化,还可以写多个上下文等等。这种就是我们自定义的开发,这种好处很明显,就是可以很好的进行扩展和自定义处理,而且匹配多个上下文,还可以支持事务等等,如果自己能力较高,或者说,身边正好有这么一个项目案例,可以对比着学习学习,搭建搭建,今天我就不详细的说这个了,下次给大家详细说明,大家这个时候应该懂了,我们开发 Ids4 的思路,无非就是一个持久化的过程,之所以使用 Ids4 这个框架,仅仅是使用了 Ids4 封装了很丰富的、去中心化的 Token 生成机制而已。

我这里简单举个例子,可以这么配置,看个思路就行了,代码不完整,我以后会详细说明,这里仅仅是展示一下:

// 配置上下文public class MyDbContext : DbContext, IConfigurationDbContext {     private readonly ConfigurationStoreOptions storeOptions;
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options) { }public DbSet<User> User { get; set; } public DbSet<Role> Roles { get; set; } public DbSet<ApiResource> ApiResources { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.ConfigureClientContext(storeOptions); modelBuilder.ConfigureResourcesContext(storeOptions);
base.OnModelCreating(modelBuilder); } }

// 正常的注入服务services.AddDbContext<MyDbContext>(builder => builder.UseOracle(connectionString, options => { options.MigrationsAssembly(migrationsAssembly); options.MigrationsHistoryTable("xxxx"); }));

 

上边的实体类可以自定义处理,然后我们再写一个仓储,或者是一个类,来处理数据:

    public class UserRepository    {        private readonly MyDbContext _dbContext;        public UserRepository(MyDbContext dbContext)        {            _dbContext = dbContext;        }        /// <summary>        /// 根据SubjectID查询用户信息        /// </summary>        /// <param name="subjectId">用户id</param>        /// <returns></returns>        public IdentityUser FindBySubjectId(string subjectId) {            return _dbContext.Set<User>().Where(r => r.SubjectId.Equals(subjectId)).Include(r => r.IdentityUserClaims).SingleOrDefault();        }        /// <summary>        /// 根据用户名查询用户        /// </summary>        /// <param name="username">用户</param>        /// <returns></returns>        public IdentityUser FindByUsername(string username)        {            return _dbContext.Set<User>().Where(r => r.Username.Equals(username)).Include(r => r.IdentityUserClaims).SingleOrDefault();        }}

 

但是如果自己能力不是很高,或者说不想太麻烦的话,可以使用 IdentityServer4 中 Identity 自带的,封装好的一套逻辑来处理,就比如我之前来处理用户数据的时候,用的就是 UserManager 类,我们这时候就使用一个 RoleManager.cs 类。

 

 3、使用NetCore自带 Identity 库

 

这个其实是很简单的,我们看一下 UserManager 类的命名空间就知道了,这个是微软原生自带的类库,和 Ids4 其实没有太大的关系:

 

 

这个类库的名字和 Ids4 也很像,就是叫做 Identity ,一共七个表,来处理用户和角色的关系:

 

 

很简单,很方便,也很丰富,那今天我们就先说说这个第二种方案,第一种方案,我们下次再说。

 

 

 

 三、利用 Identity 原生结构,处理角色信息

 

 1、自定义 Role 扩展实体类

我们既然要对 Role 进行管理,那我们就需要做下封装,Ids4 默认自带的 IdentityRole 表,仅仅只要三个属性:

public virtual TKey Id {get;set}public virtual string Name{get;set}public virtual string NormalizedName{get;set}

 

这是肯定不够用的,不仅不够用,我们还需要和资源服务器 Blog.Core 项目打通,所以两个实体类要取并集,就是求最全的属性,那我就自定义了一个应用角色表,用来满足和 Blog.Core 项目的统一:

在项目的 Models 文件夹下,新建 ApplicationRole.cs 类:

// Add profile data for application roles by adding properties to the ApplicationRole classpublic class ApplicationRole : IdentityRole<int>{
public bool IsDeleted { get; set; } public string Description { get; set; } /// <summary> ///排序 /// </summary> public int OrderSort { get; set; } /// <summary> /// 是否激活 /// </summary> public bool Enabled { get; set; } /// <summary> /// 创建ID /// </summary> public int? CreateId { get; set; } /// <summary> /// 创建者 /// </summary> public string CreateBy { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime? CreateTime { get; set; } = DateTime.Now; /// <summary> /// 修改ID /// </summary> public int? ModifyId { get; set; } /// <summary> /// 修改者 /// </summary> public string ModifyBy { get; set; } /// <summary> /// 修改时间 /// </summary> public DateTime? ModifyTime { get; set; } = DateTime.Now;
// 同理我们需要创建一个 ApplicationUserRole 关系表,具体的看我源码吧 public ICollection<ApplicationUserRole> UserRoles { get; set; }

 

这里可以做任何的自定义,只不过这里有一个小的问题,那就是这个 Id 的问题,我们的 Blog.Core 项目使用的是 Int 整型自增,那 IdentityServer4 用的是 string 方式,所以说,这里要做下处理,一般有两种办法,一种是把 IdentityServer4 项目的string 全部切换成 int,然后还有一种,就是修改 Blog.Core 资源服务器的主键 Id 为 Guid string .

其实这两种都可以,而且一般人都是采用的 Guid 和 string 的形式,但是很不巧的是,我的 Blog.Core 项目使用的是 Int 类型,所以,这里我就统一修改成 int,大家根据需要自己处理吧,具体如何处理 int 呢,大家多注意下文的类型就行,我会点明注意的点。

 

 2、修改注入的 Identity 服务

我们需要把我们的 ApplicationRole 信息也注入到服务里去,这里不多说:

services.AddIdentity<ApplicationUser, ApplicationRole>()    .AddEntityFrameworkStores<ApplicationDbContext>()    .AddDefaultTokenProviders();

 

3、修改应用上下文

因为我们自定义了 ApplicationRole ,所以在数据库上下文中,也需要对 Role 信息单独做处理,而且还比较麻烦,这个具体的,可以通过 F12 查看源码就能了解到相应的逻辑,咱们就直接这么修改:

// 注意下 红色的 int类型,到时候创建的表的主键是 int 类型的。 public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, int, IdentityUserClaim<int>, ApplicationUserRole, IdentityUserLogin<int>, IdentityRoleClaim<int>, IdentityUserToken<int>> {     public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)         : base(options)     {     }
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder);
builder.Entity<ApplicationUserRole>(userRole => { userRole.HasKey(ur => new { ur.UserId, ur.RoleId });
userRole.HasOne(ur => ur.Role) .WithMany(r => r.UserRoles) .HasForeignKey(ur => ur.RoleId) .IsRequired();
userRole.HasOne(ur => ur.User) .WithMany(r => r.UserRoles) .HasForeignKey(ur => ur.UserId) .IsRequired(); });
builder.Entity<ApplicationRole>() .ToTable("Role"); }

 

 

4、数据库迁移,生成 DB

打开我们的控制台:工具 -》Nuget 包管理器 -》程序包管理器控制台,

1、add-migration UpdateRole -Context ApplicationDbContext

2、update-database -Context ApplicationDbContext 

 

这里来一个动图:

 

 

然后我们可以看看生成的数据库表结构,可以看到,和之前的表结构,几乎是一样的,可以看到我们右侧的 Identity 生成的表结构,不仅主键变成了一样的 Int 类型,相关的属性字段也都有,如果你有强迫症的话,也可以把字段的长度设为一致,还记得在哪里修改把,就是上下文里,这里不多说:

 

  

这里有一个要注意一下,如果我们什么都不操作,默认生成的数据库表名是 AspNetRoles ,我们也可以自定义修改成自己的表名,直接修改实体类名是不行的,因为我们可以看一下生成的迁移记录,无论修改成什么,只要我们的扩展实体类是继承了类IdentityRole,那表名还是默认的 AspNetRoles:

 

 

那我们可以通过配置EFCore 的实体映射来做相应的处理,还记得我们刚刚的上下文么,就是这里:

 

 

然后我们做一下数据库迁移,最后我们可以看到数据库表名已经变了,具体的可以查看上边的迁移对比图。

完成!是不是这么写已经完成了呢,不是的,现在只是完成了一半,剩下的一半,就是在控制器里,去进行业务逻辑设计了。 

 

5、设计角色的 CURD 页面与业务逻辑

先构造函数注入下我们的 RoleManager 服务,这是 IdentityServer4 已经给我们封装好的类:

 

 

然后设计接口,主要就是增删改查,很简单,当然,你也可以像用户管理那样,带上权限信息:

[HttpGet] [Route("account/Roleregister")] public IActionResult RoleRegister(string returnUrl = null) {     ViewData["ReturnUrl"] = returnUrl;     return View(); }
[HttpPost] [Route("account/Roleregister")] [ValidateAntiForgeryToken] public async Task<IActionResult> RoleRegister(RoleRegisterViewModel model, string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; IdentityResult result = new IdentityResult();
if (ModelState.IsValid) { var roleItem = _roleManager.FindByNameAsync(model.RoleName).Result;
if (roleItem == null) { var role = new ApplicationRole { Name = model.RoleName };
result = await _roleManager.CreateAsync(role);
if (result.Succeeded) { if (result.Succeeded) { return RedirectToLocal(returnUrl); } }
} else { ModelState.AddModelError(string.Empty, $"{roleItem?.Name} already exists");
}
AddErrors(result); }
// If we got this far, something failed, redisplay form return View(model); }

[HttpGet] [Route("account/Roles")] [Authorize] public IActionResult Roles(string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; var roles = _roleManager.Roles.Where(d => !d.IsDeleted).ToList(); return View(roles); }


[HttpGet("{id}")] [Route("account/Roleedit/{id}")] [Authorize(Roles = "SuperAdmin")] public async Task<IActionResult> RoleEdit(string id, string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; if (id == null) { return NotFound(); }
var user = await _roleManager.FindByIdAsync(id);
if (user == null) { return NotFound(); }
return View(new RoleEditViewModel(user.Id, user.Name)); }

[HttpPost] [Route("account/Roleedit/{id}")] [ValidateAntiForgeryToken] [Authorize(Roles = "SuperAdmin")] public async Task<IActionResult> RoleEdit(RoleEditViewModel model, string id, string returnUrl = null) { ViewData["ReturnUrl"] = returnUrl; IdentityResult result = new IdentityResult();
if (ModelState.IsValid) { var roleItem = _roleManager.FindByIdAsync(model.Id).Result;
if (roleItem != null) { roleItem.Name = model.RoleName;
result = await _roleManager.UpdateAsync(roleItem);
if (result.Succeeded) { return RedirectToLocal(returnUrl); }
} else { ModelState.AddModelError(string.Empty, $"{roleItem?.Name} no exist!"); }
AddErrors(result); }
// If we got this far, something failed, redisplay form return View(model); }
[HttpPost] [Route("account/Roledelete/{id}")] [Authorize(Roles = "SuperAdmin")] public async Task<JsonResult> RoleDelete(string id) { IdentityResult result = new IdentityResult();
if (ModelState.IsValid) { var roleItem = _roleManager.FindByIdAsync(id).Result;
if (roleItem != null) { roleItem.IsDeleted = true;
result = await _roleManager.UpdateAsync(roleItem);
if (result.Succeeded) { return Json(result); } } else { ModelState.AddModelError(string.Empty, $"{roleItem?.Name} no exist!"); }
AddErrors(result); }
return Json(result.Errors);
}

 

那剩下的就是我们修改用户的角色信息了,毕竟我们要给用户进行加权限,也就是赋角色操作嘛。但是。

时间很晚了,篇幅太长了,今天就暂时先到这里了,总结来说,今天主要是把角色的相关操作给完整的走了一遍,还是很不错的,很有收获的,以后更精彩,下次再见。

 

 

四、Github && Gitee

https://github.com/anjoy8/Blog.IdentityServer

 

往期精彩 Ids4 文章

多项目集成统一认证中心的思考

【详细内容,点击原文,查看博客园】

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

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

相关文章

.NET Core 3.0 使用Nswag生成Api文档和客户端代码

摘要在前后端分离、Restful API盛行的年代&#xff0c;完美的接口文档&#xff0c;成了交流的纽带。在项目中引入Swagger &#xff08;也称为OpenAPI&#xff09;&#xff0c;是种不错的选择&#xff0c;它可以让接口数据可视化。下文将会演示利用Nswag如何生成Api文档利用NSwa…

深入研究 Angular 和 ASP.NET Core 3.0

本文要点&#xff1a;可以把多个 Angular 应用程序集成到 ASP.NET 网站中把 Angular 代码打包成 Web 组件是引导 Angular 应用程序的好方法可以把用 Angular 编写的 Web 组件轻松地集成到 ASP.NET 视图中把 Angular 解决方案构造成 Angular 应用程序的集合以实现更好的代码重用…

操作系统内存管理--简单、页式、段式、段页式

一、内存管理的目的和功能 内存一直是计算机系统中宝贵而又紧俏的资源&#xff0c;内存能否被有效、合理地使用&#xff0c;将直接影响到操作系统的性能。此外&#xff0c;虽然物理内存的增长现在达到了N个GB&#xff0c;但比物理内存增长还快的是程序&#xff0c;所以无论物理…

网易裁员背后,芸芸众生,相煎何急

十一月初拖家带口去了上海&#xff0c;到了著名的城隍庙参观&#xff0c;无意中看到了一个仅出现在历史书上的古老物件“西洋镜”&#xff0c;仿佛跨越百年&#xff0c;来到那个如裹脚布般冗长而乏味的古老年代&#xff0c;看到了一群有一群卑微的小民在生活的裹挟之下&#xf…

.NET Core on K8S 学习与实践系列文章索引 (更新至20191126)

更新记录&#xff1a;-- 2019-11-26 增加Docker容器日志系列文章近期在学习Kubernetes&#xff0c;基于之前做笔记的习惯&#xff0c;已经写了一部分文章&#xff0c;因此给自己立一个flag&#xff1a;完成这个《.NET Core on K8S学习实践》系列文章&#xff01;这个系列会持续…

ASP.NET Core gRPC 使用 Consul 服务注册发现

一. 前言gRPC 在当前最常见的应用就是在微服务场景中&#xff0c;所以不可避免的会有服务注册与发现问题&#xff0c;我们使用gRPC实现的服务可以使用 Consul 或者 etcd 作为服务注册与发现中心&#xff0c;本文主要介绍Consul。二. Consul 介绍Consul是一种服务网络解决方案&a…

Excel催化剂插件功能修复与更新汇总篇之十

在半年时间里&#xff0c;自己使用过程中&#xff0c;发现的一些小bug&#xff0c;更新了一下&#xff0c;也追加了一些自定义函数&#xff0c;不成系统&#xff0c;就单独放在修复与更新系列中。一、第24波-批量发送邮件并指点不同附件不同变量Excel催化剂功能第24波-批量发送…

OSI/RM 开放系统互联参考模型

开放式系统互联通信参考模型&#xff08;即&#xff1a;Open System Interconnection Reference Model&#xff0c;简称为OSI模型&#xff0c;由国际标准化组织&#xff08;ISO&#xff09;提出&#xff0c;一个试图使各种计算机在世界范围内互连为网络的标准框架。 OSI的七层体…

Http benchmarking 工具 wrk 基本使用

Http benchmarking 工具 wrk 基本使用Introwrk 是一款现代HTTP基准测试工具&#xff0c;能够在单个多核CPU上运行时产生显着负载。它将多线程设计与可扩展事件通知系统&#xff08;如epoll和kqueue&#xff09;结合在一起。官方描述&#xff1a;wrk is a modern HTTP benchmark…

TCP/IP 体系结构

TCP/IP体系结构又称为TCP/IP协议簇&#xff0c;是Transmission Control Protocol/Internet Protocol的简写&#xff0c;译为传输控制协议/因特网互联协议。 TCP/IP提供点对点的链接机制&#xff0c;将数据应该如何封装、定址、传输、路由以及在目的地如何接收&#xff0c;都加以…

黑客之道-解码Facebook的DevOps之路

内容来源&#xff1a;DevOps案例深度研究第3期 – Facebook DevOps实践研究战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;更多细节请关注案例分享会&#xff0c;及本公众号。&#xff09;本案例内容贡献者&#xff1a;张楠&#xff08;Topic Leader&#xff09;、高…

IP地址与MAC地址的区别

IP地址是指互联网协议地址&#xff08;Internet Protocol Address&#xff09;&#xff0c;是IP Address的缩写。IP地址是IP协议提供的一种统一的地址格式&#xff0c;它为互联网上的每一个网络和每一台主机分配一个逻辑地址&#xff0c;以此来屏蔽物理地址的差异。 MAC地址又称…

ping命令整个过程详解

转自&#xff1a;http://wanicy.blog.51cto.com/509018/335207/ 如果你想了解ping命令的原理&#xff0c;看了这篇文章&#xff0c;你会从对网络一窍不通&#xff0c;到豁然开朗。 先看拓朴图&#xff1a; 在这里讲ping的两情况&#xff1a;一种是同一网段内&#xff0c;一种…

ping某个域名的详细过程

在前一篇文章中&#xff0c;我们已经对ping命令的整个过程做了一个详解。但是&#xff0c;前一篇文章中所涉及到的两种ping命令使用情况&#xff0c;都是ping的IP&#xff0c;在这篇文章中&#xff0c;我们将要详细讲解ping某个域名的整个过程。 一、ICMP协议 在了解ping命令之…

Magicodes.IE之导入学生数据教程

基础教程之导入学生数据说明本教程主要说明如果使用Magicodes.IE.Excel完成学生数据的Excel导入。要点本教程使用Magicodes.IE.Excel来完成Excel数据导入需要通过创建Dto来完成导入Magicodes.IE.Excel可以根据Dto以及特性设置来自动生成导入的Excel模板&#xff0c;数据验证&am…

IP地址分类详解

一、IP地址简介 IP&#xff0c;即网际协议&#xff08;Internet Protocol&#xff09;&#xff0c;或称互联网协议&#xff0c;是用于报文交换网络的一种面向数据的协议。 IP是在TCP/IP协议中网络层的主要协议&#xff0c;任务是仅仅根据源主机和目的主机的地址传送数据。为此目…

[ASP.NET Core 3框架揭秘] 文件系统[1]:抽象的“文件系统”

ASP.NET Core应用 具有很多读取文件的场景&#xff0c;比如配置文件、静态Web资源文件&#xff08;比如CSS、JavaScript和图片文件等&#xff09;以及MVC应用的View文件&#xff0c;甚至是直接编译到程序集中的内嵌资源文件。这些文件的读取都需要使用到一个IFileProvider对象。…

[原]调试PInvoke导致的内存破坏

缘起 最近项目中遇到一个诡异的问题&#xff0c;程序在升级到.net4.6.1后&#xff0c;执行某个功能时会崩溃&#xff0c;提示访问只读内存区。大概规律如下:debug版不崩溃&#xff0c;release版稳定崩溃。只有x64位的程序崩溃&#xff0c;32位及anycpu编译出来的程序运行不会崩…

被忽略的TraceId,可以用起来了

前言.NetCore日志&#xff0c;相信大家多少都接触过&#xff0c;博客园有关 ① AspNetCore依赖注入第三方日志组件 ②第三方日志组件Nlog,Serilog 应用方法的博文层出不穷。结合程序的部署结构&#xff0c;本文分单体和微服务聊一聊AspNetCore中追踪日志流的方法。TraceIdAsp…

TCP协议详解

一、TCP协议简介 TCP协议&#xff0c;即传输控制协议&#xff08;Transmission Control Protocol&#xff09;&#xff0c;是一种面向连接的、可靠的、基于字节流的传输层通信协议。在因特网协议族中&#xff0c;TCP层是位于IP层之上&#xff0c;应用层之下的中间层。尽管IP层只…