.NET Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal
在 DotNetCore 当中不再像 MVC5 那样可以通过 HttpContext.Current 来获取到当前请求的上下文。
不过微软提供了一个 IHttpContextAccessor 来让我们访问当前请求的 Http 上下文,其定义
如下:
namespace Microsoft.AspNetCore.Http
{
public interface IHttpContextAccessor
{
HttpContext HttpContext { get; set; }
}
}
需要使用的话需要将其添加到 Ioc 容器当中,在 Startup 类的 ConfigureService 我们可以将其默认实现注册到 Ioc 之中。
public void ConfigureService(IServiceCollection services)
{
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
那么我们可以来看看 HttpContextAccessor 的具体实现:
using System.Threading;
namespace Microsoft.AspNetCore.Http
{
public class HttpContextAccessor : IHttpContextAccessor
{
private static AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>();
public HttpContext HttpContext
{
get
{
return _httpContextCurrent.Value;
}
set
{
_httpContextCurrent.Value = value;
}
}
}
}
在其内部主要是用了一个 AsyncLocal<HttpContext> 来保存一个 HttpContext 实例,那么 Accessor 是什么时候被赋值的呢?答案就是在每次 HTTP 请求的时候会将其赋值。
AsyncLocal<T> 是什么东西?
AsyncLocal<T> 是在 .Net 4.6 之后推出的一个对象,该对象接受一个泛型参数,其主要作用是保存异步等待上下文中共享某个变量的值。
而异步方法是基于 Task 的自动线程调度,在异步上下文切换的时候可能导致数据丢失。例如在 await 调用之前对某个变量进行了赋值,而这个变量是多个线程间共享的,当 await 调用返回之前的调用点的时候,可能调用点之后的代码还处在之前的线程上,也有可能被调度到其他线程上。
举个例子:
static async Task TestMethod()
{
Console.WriteLine($"当前线程ID{Thread.CurrentThread.ManagedThreadId}");
await Task.Delay(100);
Console.WriteLine($"当前线程ID{Thread.CurrentThread.ManagedThreadId}");
}
在 await 等待任务执行完成之后,后面的代码输出的 ID 与调用之前的 ID 不一样,说明发生了线程切换:
static void Main(string[] args)
{
Action @delegate = async () => await TestMethod();
@delegate();
Console.ReadKey();
}

从代码上看他们似乎在同一个线程,但是在执行的时候就已经发生了线程切换的操作了。
而我们在这里如果使用一个 ThreadLocal<T>变量来存储的话,会发生什么事情呢?
static ThreadLocal<int> _threadLocal = new ThreadLocal<int>();
static AsyncLocal<int> _asyncLocal = new AsyncLocal<int>();
static void Main(string[] args)
{
Action @delegate = async () => await TestMethod();
@delegate();
Console.ReadKey();
}
static async Task TestMethod()
{
_threadLocal.Value = 1000;
_asyncLocal.Value = 2000;
Console.WriteLine($"当前线程ID{Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"{nameof(_threadLocal)},值:{_threadLocal.Value}");
Console.WriteLine($"{nameof(_asyncLocal)},值:{_asyncLocal.Value}");
await Task.Delay(100);
Console.WriteLine($"当前线程ID{Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"{nameof(_threadLocal)},值:{_threadLocal.Value}");
Console.WriteLine($"{nameof(_asyncLocal)},值:{_asyncLocal.Value}");
}

SO,在这里解释一下,ThreadLocal 是用于为不同的线程保存不同的变量值的,即同一个变量在不同线程当中存储的值可以不一样。在这里使用是为了保证在 TestMethod 方法中变量的唯一性,这个在同步方法用是没问题的,但这里使用了 await 关键字导致等待异步调用结束后代码已经被调度到其他的线程了,所以这里没用。而 AsyncLocal<T> 正是为了这种情况而准备的。
.NET Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal的更多相关文章
- [C#].Net Core 获取 HttpContext.Current 以及 AsyncLocal 与 ThreadLocal
在 DotNetCore 当中不再像 MVC5 那样可以通过 HttpContext.Current 来获取到当前请求的上下文. 不过微软提供了一个 IHttpContextAccessor 来让我们 ...
- asp.net core获取HttpContext相关操作
建立类: using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;us ...
- 在ASP.NET Core中怎么使用HttpContext.Current
一.前言 我们都知道,ASP.NET Core作为最新的框架,在MVC5和ASP.NET WebForm的基础上做了大量的重构.如果我们想使用以前版本中的HttpContext.Current的话,目 ...
- NET Core中怎么使用HttpContext.Current
NET Core中怎么使用HttpContext.Current 阅读目录 一.前言 二.IHttpContextAccessor 三.HttpContextAccessor 回到目录 一.前言 我们 ...
- 在ASP.NET Core中怎么使用HttpContext.Current (转载)
一.前言 我们都知道,ASP.NET Core作为最新的框架,在MVC5和ASP.NET WebForm的基础上做了大量的重构.如果我们想使用以前版本中的HttpContext.Current的话,目 ...
- 为什么获取的System.Web.HttpContext.Current值为null,HttpContext对象为null时如何获取程序(站点)的根目录
ASP.NET提供了静态属性System.Web.HttpContext.Current,因此获取HttpContext对象就非常方便了.也正是因为这个原因,所以我们经常能见到直接访问System.W ...
- 在.net Core 中像以前那样的使用HttpContext.Current
今晚在学习.net Core 的使用 拿来以前项目进行改造最简单的问题就是怎么做到让httpcontext 和以前兼容 ,折腾的很久 终于搞定,纪录一下 .net core中使用了无处不在的注入,看了 ...
- System.Web.HttpContext.Current.Session获取值出错
在自定义类库CS文件里使用System.Web.HttpContext.Current.Session获取Session时提示错误:未将对象引用设置到对象的实例. 一般情况下通过这种方式获取Sessi ...
- asp.net中处理程序调用HttpContext.Current.Session获取值出错
asp.net中处理程序调用System.Web.HttpContext.Current.Session获取Session时提示错误:未将对象引用设置到对象的实例. 解决办法:在处理程序文件类中实现I ...
随机推荐
- python数据结构(二)------列表
本文将重点梳理列表及列表操作. 2.1 list函数 2.2 基本列表操作 2.3 列表方法 2.1 list函数 >>>list('hello') ['h','e','l',l', ...
- Spring-boot集成RabbitMQ踩过的坑
1.java.net.SocketException: socket closed 官方文档已经说明,新建user和guest的账户是没有远程登录的权限的 需要对登录所用账户授权 解决方法: rabb ...
- hashtable and hashmap
hashmap的bucket 和 ‘负载因子’的介绍 https://blog.csdn.net/wenyiqingnianiii/article/details/52204136
- 用STS构建spring boot
操作步骤:1. 登录地址http://spring.io/tools 下载sts,spring-tool-suite-3.9.5.RELEASE-e4.8.0-win32-x86_64.zip2. 解 ...
- java -version显示版本和JAvA_HOME配置不一样
当你需要安装多个版本的jdk时,可能会遇到更改了JAVA_HOME后java -version不变的情况. 一般情况下,将你的JAVA_HOME改为你要用的jdk的安装路径,然后你使用的就是这个版本的 ...
- Ado.Net 注意事项
Ado.Net同一个connection创建sqlCommand时,如果command要执行多个sql及其 params,这是如果某2个params中存在重名的话会报错, 例如sql1和params1 ...
- 【转】RPC介绍
转自:http://www.cnblogs.com/Vincentlu/p/4185299.html 摘要: RPC——Remote Procedure Call Protocol,这是广义上的解释, ...
- uiautomatorviewer 优化定位符生成,支持生成Java,Python自动化代码
项目介绍 二次开发 uiautomatorviewer 优化定位符生成,支持生成Java,Python自动化代码,修复自带工具画面有动态加载时截图失败问题,优化自带工具截图速度 ,实现类似录制脚本功能 ...
- ubuntu16 mysql在线安装
输入"sudo apt-get update"-->回车-->"输入root用户的密码"-->回车: 输入"sudo apt-get ...
- 画PCB之电流与线宽的关系
来源:(多图) 超强整理!PCB设计之电流与线宽的关系http://www.51hei.com/bbs/dpj-39134-1.html 关于PCB线宽和电流的经验公式,关系表和软件网上都很多,本文把 ...