#author("2023-11-20T19:17:30+08:00","default:Admin","Admin")
#author("2023-11-25T17:29:24+08:00","default:Admin","Admin")
[[ASP.NET Core Web]]

&color(red){※This article is based on .NET 7};

#contents

* 概要 [#t17da002]

ASP.NET Core应用开发中使用频率最高的对象。要说明HttpContext的本质,还得从请求处理管道的层面来讲。

对于由一个服务器和多个中间件构建的管道来说,面向传输层的服务器负责请求的监听、接收和最终的响应,当它接收到客户端发送的请求后,需要将它分发给后续中间件进行处理。

对于某个中间件来说,当我们完成了自身的请求处理任务之后,在大部分情况下也需要将请求分发给后续的中间件。请求在服务器与中间件之间,以及在中间件之间的分发是通过共享上下文的方式实现的。

当服务器接收到请求之后,会创建一个通过HttpContext表示的上下文对象,所有中间件都是在这个上下文中处理请求的,那么一个HttpContext对象究竟携带怎样的上下文信息呢?


* 举例 [#redf85ec]

我们知道一个HTTP事务(Transaction)具有非常清晰的界定,即接收请求、发送响应,所以请求和响应是两个基本的要素,也是HttpContext承载的最核心的上下文信息。

我们可以将请求理解为输入、响应理解为输出,所以应用程序可以利用HttpContext得到当前请求所有的输入信息,也可以利用它完成我们所需的所有输出工作。为此我们为ASP.NET Core Mini定义了如下这个极简版本的HttpContext。

#codeprettify{{
public class HttpContext
{           
    public  HttpRequest Request { get; }
    public  HttpResponse Response { get; }
}
public class HttpRequest
{
    public  Uri Url { get; }
    public  NameValueCollection Headers { get; }
    public  Stream Body { get; }
}
public class HttpResponse
{
    public  NameValueCollection Headers { get; }
    public  Stream Body { get; }
    public int StatusCode { get; set;}
}
}}
如上面的代码片段所示,HttpContext通过它的两个属性Request和Response来表示请求和响应,它们对应的类型分别为HttpRequest和HttpResponse。通过前者,我们可以得到请求的地址、手部集合和主体内容,利用后者,我们可以设置响应状态码,也可以设置首部和主体内容。

* 调用HttpContext [#jeacfe70]

在 ASP.NET Core 中要想得到 cookie 必须要有 Request 对象,要想得到 Request 对象 必须要有 HttpContext,要想得到 HttpContext 必须要利用 IHttpContextAccessor 接口

ASP.NET Core 中就内置了一个实现了该接口的 HttpContextAccessor 类
#codeprettify{{
命名空间:Microsoft.AspNetCore.Http
程序集:Microsoft.AspNetCore.Http.Abstractions.dll
包:Microsoft.AspNetCore.App.Ref v7.0.5
public interface IHttpContextAccessor
{
    HttpContext HttpContext { get; set; }
}
}}

** 内置标准方法 [#g6a0f201]

*** 依赖注入 [#e5df9b70]
#codeprettify{{
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    //IHttpContextAccessor register
    services.AddHttpContextAccessor();
    services.AddTransient<IUserService, UserService>();
}
}}

*** 使用 [#s31e91fc]

将 IHttpContextAccessor 注入到创建的服务构造函数中,并访问 HttpContext 的属性,如下所示:

#codeprettify{{
namespace Get_HttpContext_ASP.NET_Core
{
    using Microsoft.AspNetCore.Http;

    public class UserService : IUserService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public UserService(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        public string GetLoginUserName()
        {
            return _httpContextAccessor.HttpContext.User.Identity.Name;
        }
    }
}
}}

 https://www.telerik.com/blogs/how-to-get-httpcontext-asp-net-core

** 进阶方法 [#k9f6840f]

不直接使用父类 Controller 的 Request 和 HttpContext,这是因为此方式是一种强依赖,接下来给大家演示如何通过依赖注入的方式获取 HttpContext,此种更加灵活。


*** 依赖注入 [#p3c9741a]
自定义一个Accessor
#codeprettify{{
public class HttpContextAccessor : IHttpContextAccessor
{
    public HttpContextAccessor();
    public HttpContext HttpContext { get; set; }
}
}}

为了实现依赖注入,需要将 IHttpContextAccessor 和 HttpContextAccessor 注入到 ServiceCollection 中,下面就用单例的模式进行注入
#codeprettify{{
public void ConfigureServices(IServiceCollection services)
{
	services.AddSingleton<IHttpContextAccessor,HttpContextAccessor>();
	// 逻辑代码
}
}}

如果提示下面的报错,也是因为HttpContextAccessor没有注入导致的
 Microsoft.AspNetCore.Authorization.Policy.PolicyEvaluator': Unable to resolve service for type 'Microsoft.AspNetCore.Http.HttpContextAccessor' while attempting to activate 
*** 写入 [#ceb1e433]

然后就可以通过依赖注入的方式获取 IHttpContextAccessor 接口的实例,再依次获取 HttpContext 对象,下面的代码片段展示了如何在 Controller 中访问 IHttpContextAccessor 实例

#codeprettify{{
public class HomeController : Controller
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    public HomeController(IHttpContextAccessor httpContextAccessor)
    {
        this._httpContextAccessor = httpContextAccessor;
    }   

    //写入Cookie
    public IActionResult Write(string key, string value, bool isPersistent)
    {
    	CookieOptions options = new CookieOptions();
    	if (isPersistent)
    		options.Expires = DateTime.Now.AddDays(1);
    	else
    		options.Expires = DateTime.Now.AddSeconds(10);
    	_httpContextAccessor.HttpContext.Response.Cookies.Append(key, value, options);
    	return View("WriteCookie");
    }  
}
}}
*** 读取 [#cac81576]

#codeprettify{{
public IActionResult Read(string key)
{
	ViewBag.Data = _httpContextAccessor.HttpContext.Request.Cookies[key];
	return View("ReadCookie");
}
}}

#hr();
コメント:
#comment_kcaptcha

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS