前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >采用”传统”方式获取当前HttpContext

采用”传统”方式获取当前HttpContext

作者头像
蒋金楠
发布于 2020-11-24 07:08:33
发布于 2020-11-24 07:08:33
62200
代码可运行
举报
文章被收录于专栏:大内老A大内老A
运行总次数:0
代码可运行

我们知道“依赖注入”已经成为了.NET Core的基本编程模式,表示当前请求上下文的HttpContext可以通过注入的IHttpContextAccessor服务来提取。有时候我们会使用一些由于某些原因无法使用依赖注入的组件,我们如何提取当前HttpContext呢?

要回答这个问题,就得先来了解表示当前HTTP请求上下文的HttpContext对象被存储在什么地方?既然我们可以利用注入的IHttpContextAccessor服务来得到当前HttpContext,针对HttpContext的获取逻辑自然就体现在该接口的实现类型HttpContextAccessor上。于是反编译(也可以直接从github上获取源代码)该类型,得到它的源代码。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class HttpContextAccessor : IHttpContextAccessor
{
    // Fields
    private static AsyncLocal<HttpContextHolder> _httpContextCurrent = new AsyncLocal<HttpContextHolder>();

    // Properties
    public HttpContext HttpContext
    {
        get
        {
            HttpContextHolder local1 = _httpContextCurrent.Value;
            if (local1 != null)
            {
                return local1.Context;
            }
            HttpContextHolder local2 = local1;
            return null;
        }
        set
        {
            HttpContextHolder holder = _httpContextCurrent.Value;
            if (holder != null)
            {
                holder.Context = null;
            }
            if (value != null)
            {
                HttpContextHolder holder1 = new HttpContextHolder();
                holder1.Context = value;
                _httpContextCurrent.set_Value(holder1);
            }
        }
    }

    // Nested Types
    private class HttpContextHolder
    {
        // Fields
        public HttpContext Context;
    }
}

上代码片段可以看出,当前HttpContext被存储在静态字段表示的一个AsyncLocal<HttpContextHolder> 对象上(HttpContext被HttpContextHolder对象进一步封装),这也是为何ASP.NET Core处理请求异步调用链(通过await关键字)总是可以获取当前HttpContext的原因所在。但是这里涉及到的HttpContextHolder是一个内嵌私有类型,所以我们只有通过反射的方式来获取它封装的HttpContext对象。但是我们又不愿意承受反射带来的性能代价,那个表达式树自然成为了我们的首选解决方案。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static class HttpContextUtility
{
    private static Func<object> _asyncLocalAccessor;
    private static Func<object, object> _holderAccessor;
    private static Func<object, HttpContext> _httpContextAccessor;
    public static HttpContext GetCurrentHttpContext()
    {
        var asyncLocal = (_asyncLocalAccessor ??= CreateAsyncLocalAccessor())();
        if (asyncLocal == null)
        {
            return null;
        }

        var holder = (_holderAccessor ??= CreateHolderAccessor(asyncLocal))(asyncLocal);
        if (holder == null)
        {
            return null;
        }

        return (_httpContextAccessor ??= CreateHttpContextAccessor(holder))(holder);

        static Func<object> CreateAsyncLocalAccessor()
        {
            var fieldInfo = typeof(HttpContextAccessor).GetField("_httpContextCurrent", BindingFlags.Static | BindingFlags.NonPublic);
            var field = Expression.Field(null, fieldInfo);
            return Expression.Lambda<Func<object>>(field).Compile();
        }

        static Func<object, object> CreateHolderAccessor(object asyncLocal)
        {
            var holderType = asyncLocal.GetType().GetGenericArguments()[0];
            var method = typeof(AsyncLocal<>).MakeGenericType(holderType).GetProperty("Value").GetGetMethod();
            var target = Expression.Parameter(typeof(object));
            var convert = Expression.Convert(target, asyncLocal.GetType());
            var getValue = Expression.Call(convert, method);
            return Expression.Lambda<Func<object, object>>(getValue, target).Compile();
        }

        static Func<object, HttpContext> CreateHttpContextAccessor(object holder)
        {
            var target = Expression.Parameter(typeof(object));
            var convert = Expression.Convert(target, holder.GetType());
            var field = Expression.Field(convert, "Context");
            var convertAsResult = Expression.Convert(field, typeof(HttpContext));
            return Expression.Lambda<Func<object, HttpContext>>(convertAsResult, target).Compile();
        }
    }

}

上面的代码体现了采用表达式树实现的针对当前HttpContext的获取逻辑。具体来说,静态方法GetCurrentHttpContext利用表达式创建的Func<object>对象得到HttpContextAccessor静态字段_httpContextAccessor存储的AsyncLocal<HttpContextHolder>,然后再利用表达式创建的Func<object, object>得到该对象Value属性表示的HttpContextHolder对象。我们最终获得的HttpContext是通过由表达式创建的另一个Func<object,object>从HttpContextHolder对象中提取出来的。GetCurrentHttpContext针对当前HttpContext的提取可以通过如下的程序来验证。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class Program
{
    public static void Main(string[] args)
    {
        Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(web => web
                .ConfigureServices(svcs => svcs.AddHttpContextAccessor())
                .Configure(app => app.Run(httpContext =>
                {
                    var httpContextAccessor = httpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
                    Debug.Assert(ReferenceEquals(httpContext, HttpContextUtility.GetCurrentHttpContext()));
                    Debug.Assert(ReferenceEquals(httpContextAccessor.HttpContext, HttpContextUtility.GetCurrentHttpContext()));
                    return httpContext.Response.WriteAsync("Hello world.");
                })))
            .Build()
            .Run();
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-11-17 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
SilverLight企业应用框架设计【三】服务端设计
Type serviceType = WCFRouteTable.GetWCFType(relativeAddress);
liulun
2022/05/09
2330
FeatureCollection
ASP.NET Core管道虽然在结构组成上显得非常简单,但是在具体实现上却涉及到太多的对象,所以我们在 “通过重建Hosting系统理解HTTP请求在ASP.NET Core管道中的处理流程”(上篇、中篇、下篇) 中围绕着一个经过极度简化的模拟管道讲述了真实管道构建的方式以及处理HTTP请求的流程。在本系列 中,我们会还原构建模拟管道时可以舍弃和改写的部分,向读者朋友们呈现一个真是的HTTP请求处理管道。 ASP.NET Core 的请求处理管道由一个服务器与一组有序排列的中间件构成,前者仅仅完成请求监听、接收和响应这些与底层网络相关的工作,至于请求接收之后和响应之前的所有工作都交给中间件来完成。ASP.NET Core的中间件通过一个类型Func<RequestDelegate, RequestDelegate>的委托对象来表示,而RequestDelegate也是一个委托,它代表一项请求处理任务。 [本文已经同步到《ASP.NET Core框架揭秘》之中]
蒋金楠
2022/05/09
4680
FeatureCollection
升维打击,设计之道
上周在公司做了一个关于.NET Core依赖注入的培训,有人提到一个问题:如果同一个服务接口,需要注册多个服务实现类型,在消费该服务会根据当前上下文动态对选择对应的实现。这个问题我会被经常问到,我们不妨使用一个简单的例子来描述一下这个问题。假设我们需要采用ASP.NET Core MVC开发一个供前端应用消费的微服务,其中某个功能比较特殊,它需要针对消费者应用类型而采用不同的处理逻辑。我们将这个功能抽象成接口IFoobar,具体的功能实现在InvokeAsync方法中。
蒋金楠
2019/07/02
4420
基于领域驱动设计(DDD)超轻量级快速开发架构(二)动态linq查询的实现方式
https://www.cnblogs.com/neozhu/p/13174234.html
阿新
2020/06/23
9730
【愚公系列】2023年02月 WMS智能仓储系统-003.HttpContext的使用
网页和webapi程序交互是通过 HttpContext 传导,HttpContext包含了Cookie、Seesion、提交表单、上传数据、身份认证等信息。
愚公搬代码
2023/03/16
4310
【愚公系列】2023年02月 WMS智能仓储系统-003.HttpContext的使用
从 ThreadLocal 到 AsyncLocal
前些天跟大佬们在群里讨论如何在不使用构造函数,不增加方法参数的情况下把一个上下文注入到方法内部使用,得出的结论是 AsyncLocal 。感叹自己才疏学浅,居然才知道有 AsyncLocal 这种神器。于是赶紧恶补一下。
MJ.Zhou
2021/11/18
5450
C# 中的高性能动态属性访问方法
在C#编程中,动态访问对象属性是一项常见需求,尤其在构建灵活且可扩展的应用程序时更是如此。设想一下,你正在开发一个需要处理许多不同对象类型的系统,而且这些对象的属性可能会随着需求的变化而改变。如果你希望代码能够动态访问这些属性,而非对每个属性访问都进行硬编码,那么动态属性访问就变得至关重要了。
郑子铭
2025/03/27
700
C# 中的高性能动态属性访问方法
寻找性能更优秀的不可变小字典
Dictionary 是一个很常用的键值对管理数据结构。但是在性能要求严苛的情况下,字典的查找速度并不高。所以,我们需要更快的方案。
newbe36524
2020/11/08
4030
寻找性能更优秀的不可变小字典
C#快速高效率复制对象另一种方式 表达式树
Student s = new Student() { Age = 20, Id = 1, Name = "Emrys" };
郑子铭
2023/08/29
2200
C#快速高效率复制对象另一种方式 表达式树
晚绑定场景下对象属性赋值和取值可以不需要PropertyInfo
在《一句代码实现批量数据绑定》中,我通过界面控件ID与作为数据源的实体属性名之间的映射实现了批量数据绑定。由于里面频繁涉及对属性的反射——通过反射从实体对象中获取某个属性值;通过反射为控件的某个属性赋值,所以这不是一种高效的操作方式。为了提升性能,我通过IL Emit的方式创建了一个PropertyAccessor组件,以实现高效的属性操作。如果你看了我在文中给出的三种属性操作性能的测试结果,相信会对PropertyAccessor的作用有深刻的印象。[源代码从这里下载] 目录: 一、Prop
蒋金楠
2018/02/07
8490
晚绑定场景下对象属性赋值和取值可以不需要PropertyInfo
动态构建Lambda表达式实现EF动态查询
在使用Entity Framework做数据查询的时候,查询条件往往不是固定的,需要动态查询。可以通过动态构建Lamda表达式来实现动态查询。
Mr. Wei
2019/08/11
2.2K0
【c#表达式树】最完善的表达式树Expression.Dynamic的玩法
    在我第一次写博客的时候,写的第一篇文章,就是关于表达式树的,链接:https://www.cnblogs.com/1996-Chinese-Chen/p/14987967.html,其中,当时一直没有研究Expression.Dynamic的使用方法(因为网上找不到资料),就了解到是程序运行时动态去构建表达式树,举个例子,例如我们需要在我们的查询条件中去构建他是等于或者不等于,这个时候,虽然我们可以定义等于或者不定于 的BinaryExpression,然后在代码中通过switch去进行判断,使用的是Equal还是NotEqual,这中间还需要我们自己去写一个switch,如果使用了Dynamic的方法,我们就只需要找到对应的ExpressionType然后传入创建Binder的方法中,在调用Dynamic方法就可以动态的实现,各种判断操作,或者其他的调用方法,灵活度比switch更高,接下来,我们就看看如何使用Expression.Dynamic方法来实现各种操作吧,一下所有代码操作需要引入Microsoft.CSharp.RuntimeBinder,nuget搜索Microsoft.CSharp即可。方便测试,我新建了一个Test的类,下面会用到
陈显达
2023/04/17
4890
【c#表达式树】最完善的表达式树Expression.Dynamic的玩法
c#表达式树入门,看这个就够了
ps:问: 反射有3种方式,一个是获取值,一个是赋值,一个是调用方法 (如构造器 静态方法 普通方法等),哪个才是性能元凶
洪移潮
2024/10/30
1340
ASP.NET Core管道详解[4]: 中间件委托链
ASP.NET Core应用默认的请求处理管道是由注册的IServer对象和HostingApplication对象组成的,后者利用一个在创建时提供的RequestDelegate对象来处理IServer对象分发给它的请求。而RequestDelegate对象实际上是由所有的中间件按照注册顺序创建的。换句话说,这个RequestDelegate对象是对中间件委托链的体现。如果将RequestDelegate替换成原始的中间件,那么ASP.NET Core应用的请求处理管道体现为下图所示的形式。[本文节选自《ASP.NET Core 3框架揭秘》第13章, 更多关于ASP.NET Core的文章请点这里]
蒋金楠
2020/12/01
9740
ASP.NET Core管道详解[4]: 中间件委托链
四种为HttpClient添加默认请求报头的解决方案
HttpClient在Web调用中具有广泛的应用,而为它添加默认请求头是我们经常遇到的需求,本文介绍4种为HttpClient添加默认请求头的方式。
蒋金楠
2019/09/29
9960
高性能替代反射调用的几种方式
园子里和这个话题的相关文章比较多,本文是旧话重提,外加个小的总结。主要因为近期看到很多同事、朋友都已经使用 VS2012 进行 .NET 4.5 开发了,却还在大量使用反射,不知道用新的方式。或有所了解,但又害怕性能不好不敢大胆去用。 本文以如下类为例: public class MyMath { public int Add(int a, int b) { return a + b; } } 替代反射的几种方式 倒序说吧,从最先进最简单的开始。 1. dynamic 调
逸鹏
2018/04/11
1.1K0
高性能替代反射调用的几种方式
关于Expression Tree和IL Emit的所谓的"性能差别"
昨天写了《三种属性操作性能比较》,有个网友写信问我一个问题:从性能上看,Expression Tree和IL Emit孰优孰劣?虽然我在回信中作了简单的回答,但不知道这个网友是否懂我的意思。反正今天呆
蒋金楠
2018/02/08
9280
ASP.NET Core管道详解[2]: HttpContext本质论
ASP.NET Core请求处理管道由一个服务器和一组有序排列的中间件构成,所有中间件针对请求的处理都在通过HttpContext对象表示的上下文中进行。由于应用程序总是利用服务器来完成对请求的接收和响应工作,所以原始请求上下文的描述由注册的服务器类型来决定。但是ASP.NET Core需要在上层提供具有一致性的编程模型,所以我们需要一个抽象的、不依赖具体服务器类型的请求上下文描述,这就是本章着重介绍的HttpContext。[本文节选自《ASP.NET Core 3框架揭秘》第13章, 更多关于ASP.NET Core的文章请点这里]
蒋金楠
2020/11/24
1.3K1
ASP.NET Core管道详解[2]: HttpContext本质论
模拟ASP.NET Core MVC设计与实现
前几天有人在我的《ASP.NET Core框架揭秘》读者群跟我留言说:“我最近在看ASP.NET Core MVC的源代码,发现整个系统太复杂,涉及的东西太多,完全找不到方向,你能不能按照《200行代码,7个对象——让你了解ASP.NET Core框架的本质》这篇文章思路剖析一下MVC框架”。对于ASP.NET Core MVC框架的涉及和实现,说难也难,毕竟一个Model Binding就够很多人啃很久,其实说简单也简单,因为整个流程是很清晰的。ASP.NET Core MVC支持基于Controller和Page的两种编程模式,虽然编程方式看起来不太一样,底层针对请求的处理流程其实是一致的。接下来,我同样使用简单的代码构建一个Mini版的MVC框架,让大家了解一下ASP.NET Core MVC背后的总体设计,以及针对请求的处理流程。[源代码从这里下载]。
蒋金楠
2023/11/09
3670
模拟ASP.NET Core MVC设计与实现
在ASP.NET Core中怎么使用HttpContext.Current
  我们都知道,ASP.NET Core作为最新的框架,在MVC5和ASP.NET WebForm的基础上做了大量的重构。如果我们想使用以前版本中的HttpContext.Current的话,目前是不可用的,因为ASP.NET Core中是并没有这个API的。
yoyofx
2018/09/05
3K0
推荐阅读
相关推荐
SilverLight企业应用框架设计【三】服务端设计
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文