全局获取HttpContext
全局获取HttpContext
在我们平常开发中会有这样的需求,我们的Service业务层需要获取请求上下文中的用户信息,一般我们从控制器参数传递过来。如果你觉得这样就可以了,请您关闭文章。
场景
但是我们也会遇到控制器传递困难的场景,我自己最近使用单库实现多租户的PAAS平台,发现EF Core上下文获取我Token或者Headers中获取租户Id进行全局过滤就很麻烦(多租户解决方案后期我补充)。
涉及知识
我们先要知道一个思想如果想要整个.NET程序中共享一个变量,我们可以将想要共享的变量放在某个类的静态属性上来实现。
但是我们的请求上下文每个人的信息不一样,就需要将这个变量的共享范围缩小到单个线程内。例如在web应用中,服务器为每个同时访问的请求分配一个独立的线程,我们要在这些独立的线程中维护自己的当前访问用户的信息时,就需要需要线程本地存储了。
- IHttpContextAccessor 设置实现规范
- HttpContextAccessor 基于当前执行上下文提供的实现。
- AsyncLocal 实现多线程中静态变量独立化 (这里画一个圈圈)
这个时候我们再看源码思路就清晰了,我们通过注入HttpContextAccessor,然后内部将请求上下文保存在_httpContextCurrent静态变量中,这个就可以全局访问啦(当然访问范围是在该主线程内部)。
// HttpContextAccessor源码
public class HttpContextAccessor : IHttpContextAccessor
{
// 通过AsyncLocal保存当前上下文信息
private static readonly AsyncLocal<HttpContextHolder> _httpContextCurrent =new AsyncLocal<HttpContextHolder>();
public HttpContext? HttpContext
{
get
{
return _httpContextCurrent.Value?.Context;
}
set
{
var holder = _httpContextCurrent.Value;
if (holder != null)
{
// 清除AsyncLocals中捕获的当前HttpContext
holder.Context = null;
}
if (value != null)
{
// 使用一个对象间接在AsyncLocal中保存HttpContext,
// 所以当它被清除时,它可以在所有的ExecutionContexts中被清除。
_httpContextCurrent.Value = new HttpContextHolder { Context =
value };
}
}
}
private class HttpContextHolder
{
public HttpContext? Context;
}
整活
首先我们需要在Startup的ConfigureServices方法中注册IHttpContextAccessor的实例
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
....
}
这个时候你Service层注入该类的时候就可以获取到请求上下文信息了,但是这个就不符合我们诗一般程序员的气质。
因为直接将请求上下文本抛出来还挺多的,我们本来只需要租户ID但是你给我一坨,挺不好把握的。
整大活
我们可以进行包装,我使用PrincipalAccessor进行请求上下文拆解

然后在Startup的ConfigureServices方法中,我们一样把这个类也加入注册中
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IPrincipalAccessor, PrincipalAccessor>();
....
}
最后自己项目的一些优化
自己不断的在优化自己的项目结构,或者设计思路,我发现我为什么有这么多注入,我构造函数都要爆了。
然后自己想了想,我其实可以将访问上下文的类放入BaseService中静态变量存储,系统提供了IServiceCollection来注册服务和提供了IServiceProvider这个让我们解析各种注册过的服务.
我们定义一个存储类
public class ServiceProviderInstance
{
public static IServiceProvider Instance { get; set; }
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
...
ServiceProviderInstance.Instance = app.ApplicationServices;
}
宝贝相信我剩下的我们交给时间,我们只需要这样(BaseService定义属性、获取注入就可以了),然后就那样(就直接可以使用啦)
public class BaseService<T, Repository> : IBaseService<T>
where T : BaseEntityCore, new()
//规定这个Repository类型一定是继承仓储的接口,下面就可以使用接口的方法
where Repository : IBaseRepository<T>
{
/// <summary>
/// 身份信息
/// </summary>
protected IClaimsAccessor Claims { get; set; }
/// <summary>
/// 获取仓储实体
/// </summary>
private readonly Repository CurrentRepository;
public BaseService(Repository currentRepository)
{
CurrentRepository = currentRepository;
Claims = ServiceProviderInstance.Instance.GetRequiredService<IClaimsAccessor>();
}
.....
}
全局获取HttpContext的更多相关文章
- .NET Core如何全局获取用户信息?
前言 在增删改查中的增和改操作中,我们经常需要更新数据流的创建人和修改人,无论我们项目是基于DDD,抑或是简单仅有服务层,此时我们都需要获取用户信息,那么我们只能将用户标识从控制器层层传递到服务或仓储 ...
- Android 全局获取 Context 与使用 Intent 传递对象
=====================全局获取 Context======================== Android 开发中很多地方需要用到 Context,比如弹出 Toast.启动活 ...
- Android 如何全局获取Context
有时,在处理业务逻辑的时候,需要Context对象,但在某些情况下,并非容易获取,这时就需要一些巧妙的手段来管理Context. 在Android中,提供了一个类Application,当应用程序启动 ...
- Android开发之全局获取Context的技巧
转自<第一行代码-Android>进阶篇 这本书对于入门来说确实很棒,很简单明了的介绍了Android开发中涉及到的方方面面,对我的帮助很大,同时记录一些该书中一些对我以后开发有用的东西, ...
- 全局获取Context的技巧
全局获取Context的技巧 在android开发中,非常多地方都要用到Context上下文这个类对象,比方:弹出 Toast 的时候须要.启动活动的时候须要.发送广播的时候须要.操作数据库的时候须要 ...
- android#全局获取Context的技巧
参考<第一行代码>——郭霖 回想这么久以来我们所学的内容,你会发现有很多地方都需要用到Context,弹出Toast的时候需要.启动活动的时候需要.发送广播的时候需要.操作数据库的时候需要 ...
- 在Spring应用中创建全局获取ApplicationContext对象
在Spring应用中创建全局获取ApplicationContext对象 1.需要创建一个类,实现接口ApplicationContextAware的setApplicationContext方法. ...
- [C#].Net Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal
在 DotNetCore 当中不再像 MVC5 那样可以通过 HttpContext.Current 来获取到当前请求的上下文. 不过微软提供了一个 IHttpContextAccessor 来让我们 ...
- .NET Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal
在 DotNetCore 当中不再像 MVC5 那样可以通过 HttpContext.Current 来获取到当前请求的上下文. 不过微软提供了一个 IHttpContextAccessor 来让我们 ...
随机推荐
- 使用Prometheus Operator 监控Kubernetes(15)
一.Prometheus概述: Prometheus是一个开源系统监测和警报工具箱. Prometheus Operator 是 CoreOS 开发的基于 Prometheus 的 Kubernete ...
- jmeter while控制器踩坑
在使用jmeter测试一个复杂流程,需要用到while控制器,对于里面的contition,使用jexl3方式,怎么看都没有问题,可是死活跳不出流程,各种莫名其妙的报错,甚至用单个写死的变量(已设置为 ...
- 什么是FOC
https://zhidao.baidu.com/question/354536332.html FOC简述 磁场定向控制系统(FOC)又称为矢量控制系统,他是选择电机某一旋转磁场轴作为特定的同步旋转 ...
- JDK5.0新特性 (Day_07)
JDK5.0新特性 目录 静态导入 自动装箱/拆箱 for-each循环 可变参数 枚举 JDK 5.0 新特性简介 JDK 5.0 的一个重要主题就是通过新增一些特性来简化开发,这些特性包括 ...
- redis 处理缓存击穿以及缓存雪崩
缓存击穿 1. 缓存击穿简述 某一个热点数据在缓存中失效,请求穿过redis到达DB,造成DB压力过大 2. 怎么解决缓存击穿 1. 使用redis 作为分布式互斥锁(mutex lock) 实现步骤 ...
- Servlet中的过滤器和监听器
1.什么是过滤器? Servlet规范中定义的一种特殊的组件,用来拦截容器的调用过程.容器收到请求之后,首先调用过滤器,然后再调用Servlet 2.生命周期: 1.servlet:servlet的生 ...
- 【Azure 事件中心】azure-spring-cloud-stream-binder-eventhubs客户端组件问题, 实践消息非顺序可达
问题描述 查阅了Azure的官方文档( 将事件发送到特定分区: https://docs.azure.cn/zh-cn/event-hubs/event-hubs-availability-and-c ...
- 【进阶之路】多线程条件下分段处理List集合的几种方法
这两个月来因为工作和家庭的事情,导致一直都很忙,没有多少时间去汲取养分,也就没有什么产出,最近稍微轻松了一点,后续的[进阶之路]会慢慢回到正轨. 开门见山的说,第一次接触到多线程处理同一个任务,是使用 ...
- mybatis运行出现org.apache.ibatis.binding.BindingException
今天学习mybatis的第一天,发现用junit测试报出了次异常:org.apache.ibatis.binding.BindingException: Type interface cn.dzp.d ...
- Python+Selenium - iframe定位
元素在iframe中.在html当中,内嵌了另一个html (iframe) 分辨元素是否在iframe当中 在代码当中,从当前的html切换到iframe当中的html,然后在元素定位 切换方式:d ...