在ASP.NET Core中怎么使用HttpContext.Current

一、前言

  我们都知道,ASP.NET Core作为最新的框架,在MVC5和ASP.NET WebForm的基础上做了大量的重构。如果我们想使用以前版本中的HttpContext.Current的话,目前是不可用的,因为ASP.NET Core中是并没有这个API的。

  当然我们也可以通过在Controller中访问HttpContext,但是某些情况下,这样使用起来还是不如HttpContext.Current方便。

二、IHttpContextAccessor

  利用ASP.NET Core的依赖注入容器系统,通过请求获取IHttpContextAccessor接口,我们拥有模拟使用HttpContext.Current这样API的可能性。但是因为IHttpContextAccessor接口默认不是由依赖注入进行实例管理的。我们先要将它注册到ServiceCollection中:

public void ConfigureServices(IServiceCollection services)
{
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    // Other code...
}

  来模拟一个HttpContext.Current吧:

 public static class HttpContext
 {
        public static IServiceProvider ServiceProvider;

        public static Microsoft.AspNetCore.Http.HttpContext Current
        {
            get
            {
                object factory = ServiceProvider.GetService(typeof(Microsoft.AspNetCore.Http.IHttpContextAccessor));
                Microsoft.AspNetCore.Http.HttpContext context = ((Microsoft.AspNetCore.Http.HttpContextAccessor)factory).HttpContext;
                return context;
            }
        }

}

 其实说到HttpContext.Current就不得不提到多线程问题,在以前的ASP.NET版本中,如果遇到多线程环境很有可能HttpContext.Current为空的情况。说到这个问题以前就是有解决方案的,那就是CallContext;

CallContext 是类似于方法调用的线程本地存储区的专用集合对象,并提供对每个逻辑执行线程都唯一的数据槽。数据槽不在其他逻辑线程上的调用上下文之间共享。当 CallContext 沿执行代码路径往返传播并且由该路径中的各个对象检查时,可将对象添加到其中。

  当使用ASP.NET的时候,虽然线城池里的线程是复用的,但是CallContext并不在一个线程的多次使用中共享。因为CallContext是针对逻辑线程的TLS,线程池中被复用的线程是操作系统中的内核对象而不是托管对象。就像数据库连接池中保存的是非托管资源而不是托管资源。因此,先后执行的两个托管线程可能在底层复用了一个物理线程(内核对象),但并不能共享同一组CallContext数据槽。就像先后new的两个SqlConnection对象可能在底层使用了同一个物理连接,但是托管对象的属性已经被重置。

  与此对照的是ThreadStaticAttribute,标记上这个特性的静态字段是往物理线程的TLS中保存数据(根据MSDN的描述猜的。具体没试过),因此如果两个托管线程对象内部使用的是同一个物理线程,则这个字段会复用(在两个线程通过这一字段访问同一个数据槽)。

  在.NET Core中,也有新的API选择,AsyncLocal<T>。

三、HttpContextAccessor

  我们来看看ASP.NET Core中的IHttpContextAccessor接口实现吧:

 public class HttpContextAccessor : IHttpContextAccessor
 {
#if NET451
        private static readonly string LogicalDataKey = "__HttpContext_Current__" + AppDomain.CurrentDomain.Id;

        public HttpContext HttpContext
        {
            get
            {
                var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle;
                return handle?.Unwrap() as HttpContext;
            }
            set
            {
                CallContext.LogicalSetData(LogicalDataKey, new ObjectHandle(value));
            }
        }

#elif NETSTANDARD1_3
        private AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>();
        public HttpContext HttpContext
        {
            get
            {
                return _httpContextCurrent.Value;
            }
            set
            {
                _httpContextCurrent.Value = value;
            }
        }
#endif
}

  最后我只能说在ASP.NET Core中是万物皆DI啊,其实Core中的实现早就为我们想好了这些功能,只是改变了使用方式。

GitHub:https://github.com/maxzhang1985/YOYOFx  如果觉还可以请Star下, 欢迎一起交流。

.NET Core 开源学习群: 214741894

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏码农阿宇

EF Core利用Transaction对数据进行回滚保护

What? 首先,说一下什么是EF Core中的Transaction Transaction允许以原子方式处理多个数据库操作,如果事务已提交,则所有操作都应用...

39450
来自专栏葡萄城控件技术团队

异步陷阱之死锁篇

提倡异步编程旨在给用户更好的前端体验,但异步编程也让学习成本和犯错几率大大升高,其中最常见且最难处理的就是死锁。 何谓“死锁”,英文术语称“Deadlock”,...

32690
来自专栏NetCore

【翻译】在Visual Studio中使用Asp.Net Core MVC创建你的第一个Web API应用(一)

HTTP is not just for serving up web pages. It’s also a powerful platform for bui...

27250
来自专栏大内老A

Enterprise Library深入解析与灵活应用(7):再谈PIAB与Unity之间的集成

在EnteLib中,PIAB(Policy Injection Application Block)和Unity的定位是轻量级的AOP框架和IoC容器(Cont...

213100
来自专栏NetCore

c#中设置快捷键

最近找了一些资料,是讲在C#中设置快捷键运行方法或程序的 要设置快捷键必须使用user32.dll下面的两个方法。 BOOL RegisterHotKey(  ...

21460
来自专栏丑胖侠

Zookeeper客户端API之创建会话(六)

Zookeeper对外提供了一套Java的客户端API。本篇博客主要讲一下创建会话。 创建项目 首选,创建一个基于maven管理的简单java工程。在pom文件...

21590
来自专栏石奈子的Java之路

原 荐 Java9之HttpClientAP

29520
来自专栏博客园

持久化方式

HttpContext抽象提供了一个简单的IDictionary<Object,Object>类型的字典集合,叫做Items。在每个请求中,这个集合从HttpR...

12920
来自专栏me的随笔

ASP.NET MVC5请求管道和生命周期

请求管道是一些用于处理HTTP请求的模块组合,在ASP.NET中,请求管道有两个核心组件:IHttpModule和IHttpHandler。所有的HTTP请求都...

16130
来自专栏晓晨的专栏

asp.net core使用jexus部署在linux无法正确 获取远程ip的解决办法

21650

扫码关注云+社区

领取腾讯云代金券