• NET Core中怎么使用HttpContext.Current


    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中:

    1. public void ConfigureServices(IServiceCollection services)
    2. {
    3. services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    4. // Other code...
    5. }

      来模拟一个HttpContext.Current吧:

    1. public static class HttpContext
    2. {
    3. public static IServiceProvider ServiceProvider;
    4. public static Microsoft.AspNetCore.Http.HttpContext Current
    5. {
    6. get
    7. {
    8. object factory = ServiceProvider.GetService(typeof(Microsoft.AspNetCore.Http.IHttpContextAccessor));
    9. Microsoft.AspNetCore.Http.HttpContext context = ((Microsoft.AspNetCore.Http.HttpContextAccessor)factory).HttpContext;
    10. return context;
    11. }
    12. }
    13. }

      其实说到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接口实现吧:

    1. public class HttpContextAccessor : IHttpContextAccessor
    2. {
    3. #if NET451
    4. private static readonly string LogicalDataKey = "__HttpContext_Current__" + AppDomain.CurrentDomain.Id;
    5. public HttpContext HttpContext
    6. {
    7. get
    8. {
    9. var handle = CallContext.LogicalGetData(LogicalDataKey) as ObjectHandle;
    10. return handle?.Unwrap() as HttpContext;
    11. }
    12. set
    13. {
    14. CallContext.LogicalSetData(LogicalDataKey, new ObjectHandle(value));
    15. }
    16. }
    17. #elif NETSTANDARD1_3
    18. private AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>();
    19. public HttpContext HttpContext
    20. {
    21. get
    22. {
    23. return _httpContextCurrent.Value;
    24. }
    25. set
    26. {
    27. _httpContextCurrent.Value = value;
    28. }
    29. }
    30. #endif
    31. }

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

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

    .NET Core 开源学习群: 214741894  

  • 相关阅读:
    C#执行异步操作的几种方式
    spring boot swagger ui使用 nginx 部署后无法使用问题
    PHP支付宝接口RSA验证
    认证加密算法php hash_hmac和java hmacSha1的问题
    如何实现从 Redis 中订阅消息转发到 WebSocket 客户端
    ffmpeg安装
    nginx静态资源反向代理
    Redis基础知识 之——发布/订阅
    linux下安装git
    php实现无限级分类查询(递归、非递归)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/6195683.html
Copyright © 2020-2023  润新知