如何在 ASP.NET Core 中获取 HttpContext.Current? [复制]
Posted
技术标签:
【中文标题】如何在 ASP.NET Core 中获取 HttpContext.Current? [复制]【英文标题】:How to get HttpContext.Current in ASP.NET Core? [duplicate] 【发布时间】:2016-11-28 23:44:31 【问题描述】:我们目前正在使用 ASP.NET Core 重写/转换我们的 ASP.NET WebForms 应用程序。尽量避免重新设计。
在类库中有一个部分我们使用HttpContext
来检查当前状态。如何在 .NET Core 1.0 中访问 HttpContext.Current
?
var current = HttpContext.Current;
if (current == null)
// do something here
// string connection = Configuration.GetConnectionString("MyDb");
我需要访问它以构建当前的应用程序主机。
$"current.Request.Url.Scheme://current.Request.Url.Host(current.Request.Url.Port == 80 ? "" : ":" + current.Request.Url.Port)";
【问题讨论】:
首先问问自己,为什么需要从类库中访问它。 80% 的情况下,没有理由,只是糟糕的设计甚至尝试。在您上面的情况下,您没有。更改类库的设计,传入您需要的参数,而不是从中访问。更少的耦合,更好的可维护代码。查看IOptions<T>
@Tseng 可以说我想通过它。那我应该通过什么?这就是这里的全部问题。 ASP.NET Core中相当于HttpContext的命名空间或对象是什么
阅读您的问题,并意识到这不是问题,它几乎没有说什么。信息如此之少,很难提供。其次,请阅读我的第一条评论以了解正确的方向
@Tseng 同时它不应该像一个不理解问题并且他们投反对票一样。你对这个问题发表了评论,如果你理解我的回答,你的评论与问题无关,它说明你根本不理解这个问题。所以像你这样的人一直在投票,这也阻止了用户使用这个平台。该平台适用于高质量的问题和高质量的答案,而不仅仅是投反对票和投赞成票。
@Tseng:在您的评论中,您没有说明为什么您认为这是一个不好的问题。这是关于为什么这个人不应该尝试做他想做的事情。人们在 ASP.NET 中的任何地方都使用HttpContext.Current
,不管他们是否应该。询问 ASP.NET Core 中的等价物是什么,我认为没有太大的危害。答案可能是没有,或者有不同/更好的方法。
【参考方案1】:
作为一般规则,将 Web 窗体或 MVC5 应用程序转换为 ASP.NET Core需要进行大量重构。
HttpContext.Current
已在 ASP.NET Core 中删除。从单独的类库访问当前的 HTTP 上下文是 ASP.NET Core 试图避免的混乱架构类型。有几种方法可以在 ASP.NET Core 中重新构建它。
HttpContext 属性
您可以通过任何控制器上的HttpContext
属性访问当前的HTTP 上下文。最接近原始代码示例的方法是将 HttpContext
传递到您正在调用的方法中:
public class HomeController : Controller
public IActionResult Index()
MyMethod(HttpContext);
// Other code
public void MyMethod(Microsoft.AspNetCore.Http.HttpContext context)
var host = $"context.Request.Scheme://context.Request.Host";
// Other code
中间件中的HttpContext参数
如果您正在为 ASP.NET Core 管道编写 custom middleware,则当前请求的 HttpContext
会自动传递到您的 Invoke
方法中:
public Task Invoke(HttpContext context)
// Do something with the current HTTP context...
HTTP 上下文访问器
最后,您可以使用IHttpContextAccessor
帮助服务来获取由 ASP.NET Core 依赖注入系统管理的任何类中的 HTTP 上下文。当您的控制器使用公共服务时,这很有用。
在你的构造函数中请求这个接口:
public MyMiddleware(IHttpContextAccessor httpContextAccessor)
_httpContextAccessor = httpContextAccessor;
然后您可以安全地访问当前的 HTTP 上下文:
var context = _httpContextAccessor.HttpContext;
// Do something with the current HTTP context...
IHttpContextAccessor
并不总是默认添加到服务容器中,所以为了安全起见,将其注册到ConfigureServices
:
public void ConfigureServices(IServiceCollection services)
services.AddHttpContextAccessor();
// if < .NET Core 2.2 use this
//services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Other code...
【讨论】:
您忘记了IHttpContextAccessor
,但是由于 RC2,它默认没有注册,因为它会带来一些请求开销。见公告github.com/aspnet/Announcements/issues/190
单例可以吗?应该改为 AddScoped 吗?
@syclee 我也想知道,但根据上面的链接(以及basic MVC sample app),我的答案中的语法是正确的。
我认为访问者可以是单例的......这只是让我们能够获取上下文的东西......所以访问(上下文)的结果通常是每个请求值。
@Nate Barbettini 在代码中的任何地方,你都在当前的 HttpContext 中,传递它没有任何好处,我是为了简单和功能,我看不出它的缺点,传递它只是让我工作更多,没有任何好处。【参考方案2】:
死灵术。
是的,你可以,这就是方法。
给那些迁移大型 junks 代码块的人的秘诀:
以下方法是一个 hack 的邪恶痈肿,它正在积极从事撒旦的快速工作(在 .NET Core 框架开发人员的眼中),但它确实有效:
在public class Startup
添加属性
public IConfigurationRoot Configuration get;
然后在ConfigureServices中给DI添加一个单例IHttpContextAccessor。
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();
然后在配置中
public void Configure(
IApplicationBuilder app
,IHostingEnvironment env
,ILoggerFactory loggerFactory
)
添加DI参数IServiceProvider svp
,所以方法如下:
public void Configure(
IApplicationBuilder app
,IHostingEnvironment env
,ILoggerFactory loggerFactory
,IServiceProvider svp)
接下来,为 System.Web 创建一个替换类:
namespace System.Web
namespace Hosting
public static class HostingEnvironment
public static bool m_IsHosted;
static HostingEnvironment()
m_IsHosted = false;
public static bool IsHosted
get
return m_IsHosted;
public static class HttpContext
public static IServiceProvider ServiceProvider;
static HttpContext()
public static Microsoft.AspNetCore.Http.HttpContext Current
get
// var factory2 = ServiceProvider.GetService<Microsoft.AspNetCore.Http.IHttpContextAccessor>();
object factory = ServiceProvider.GetService(typeof(Microsoft.AspNetCore.Http.IHttpContextAccessor));
// Microsoft.AspNetCore.Http.HttpContextAccessor fac =(Microsoft.AspNetCore.Http.HttpContextAccessor)factory;
Microsoft.AspNetCore.Http.HttpContext context = ((Microsoft.AspNetCore.Http.HttpContextAccessor)factory).HttpContext;
// context.Response.WriteAsync("Test");
return context;
// End Class HttpContext
现在在配置中,您在其中添加了IServiceProvider svp
,将此服务提供者保存到刚刚创建的虚拟类 System.Web.HttpContext (System.Web.HttpContext.ServiceProvider) 中的静态变量“ServiceProvider”中
并将 HostingEnvironment.IsHosted 设置为 true
System.Web.Hosting.HostingEnvironment.m_IsHosted = true;
这本质上是 System.Web 所做的,只是您从未见过它(我猜该变量被声明为内部变量而不是公共变量)。
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider svp)
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
ServiceProvider = svp;
System.Web.HttpContext.ServiceProvider = svp;
System.Web.Hosting.HostingEnvironment.m_IsHosted = true;
app.UseCookieAuthentication(new CookieAuthenticationOptions()
AuthenticationScheme = "MyCookieMiddlewareInstance",
LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Unauthorized/"),
AccessDeniedPath = new Microsoft.AspNetCore.Http.PathString("/Account/Forbidden/"),
AutomaticAuthenticate = true,
AutomaticChallenge = true,
CookieSecure = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest
, CookieHttpOnly=false
);
就像在 ASP.NET Web-Forms 中一样,当您尝试访问没有 HttpContext 时,您将获得 NullReference,例如它曾经位于 global.asax 中的 Application_Start
中。
我再次强调,这只有在你实际添加时才有效
services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();
就像我写的那样,你应该这样做。 欢迎使用 DI 模式中的 ServiceLocator 模式;) 对于风险和副作用,请咨询您的常驻医生或药剂师 - 或通过 github.com/aspnet 研究 .NET Core 的来源,并进行一些测试。
也许一个更易于维护的方法是添加这个帮助类
namespace System.Web
public static class HttpContext
private static Microsoft.AspNetCore.Http.IHttpContextAccessor m_httpContextAccessor;
public static void Configure(Microsoft.AspNetCore.Http.IHttpContextAccessor httpContextAccessor)
m_httpContextAccessor = httpContextAccessor;
public static Microsoft.AspNetCore.Http.HttpContext Current
get
return m_httpContextAccessor.HttpContext;
然后在Startup->Configure中调用HttpContext.Configure
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider svp)
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
System.Web.HttpContext.Configure(app.ApplicationServices.
GetRequiredService<Microsoft.AspNetCore.Http.IHttpContextAccessor>()
);
【讨论】:
请注意辅助类方式也需要运行services.AddSingleton
部分【参考方案3】:
如果您确实需要对当前上下文的静态访问,有一个解决方案。 在 Startup.Configure(….)
app.Use(async (httpContext, next) =>
CallContext.LogicalSetData("CurrentContextKey", httpContext);
try
await next();
finally
CallContext.FreeNamedDataSlot("CurrentContextKey");
);
当您需要它时,您可以通过以下方式获得它:
HttpContext context = CallContext.LogicalGetData("CurrentContextKey") as HttpContext;
我希望这会有所帮助。请记住,这种解决方法是在您别无选择时。最佳实践是使用去依赖注入。
【讨论】:
这对我不起作用,我应该能够在引用的类库中使用这一行吗? HttpContext 上下文 = CallContext.LogicalGetData("CurrentContextKey") as HttpContext;当我这样做时,上下文只是设置为空 您可以在库中使用它。但我认为你只是使用了 System.Web.HttpContext 类,它与 aspnet 核心 http 上下文(Microsoft.AspNetCore.Http.HttpContext)不是同一个类以上是关于如何在 ASP.NET Core 中获取 HttpContext.Current? [复制]的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 ASP.NET Core 3 中的中间 Web API 传递未更改的 HTTP 响应?
ASP.Net Core 如何在 EF Core 和 Identity 中获取用户角色
如何在 ASP.NET Core 中获取 HttpContext.Current? [复制]