访问ASP.NET Core中的当前HttpContext

max*_*her 113 c# asp.net-core

我需要HttpContext在静态方法或实用程序服务中访问当前.

使用经典的ASP.NET MVC System.Web,我只是用来HttpContext.Current静态访问上下文.但是我如何在ASP.NET Core中执行此操作?

Kév*_*let 129

HttpContext.Current在ASP.NET Core中不再存在但是有一个新的 IHttpContextAccessor,你可以在你的依赖项中注入并用于检索当前HttpContext:

public class MyComponent : IMyComponent
{
    private readonly IHttpContextAccessor _contextAccessor;

    public MyComponent(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public string GetDataFromSession()
    {
        return _contextAccessor.HttpContext.Session.GetString(*KEY*);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 不要使用CallContextServiceLocator (15认同)
  • @davidfowl除非你有一个有效的技术理由(当然,除了'静态是邪恶的'),我敢打赌,如果他们别无选择,人们会使用它. (9认同)
  • @tugberk,理论上,您也可以使用`CallContextServiceLocator`来解析服务,即使是从非DI注入的实例:`CallContextServiceLocator.Locator.ServiceProvider.GetService <IHttpContextAccessor>()`.在实践中,如果你可以避免它,这是一件好事:) (6认同)
  • 当然,人们很少有有效的技术理由.它更像是使用静态更容易,谁更关心可测试性:) (6认同)
  • 好点子!还值得一提的是,"IHttpContextAccessor"只能在DI容器解析实例的地方使用. (3认同)
  • 您能否提供有关如何配置此服务以及如何在控制器外访问“MyComponent”的完整代码? (3认同)
  • 我有一个非注入实例(实际上是NLog LayoutRenderer),我不能使用CallContextServiceLocator,因为它们只有7种可从ServiceLocator获得的服务,并且由于某些原因不包括IHttpContextAccessor ... (2认同)
  • 我对此感到困惑.我是第二个递归的问题.我们从哪里获取IHttpContextAccessor的实例以传递给构造函数? (2认同)
  • 如果您通过 DI 注入并*通过在“Startup”类的“ConfigureServices”方法中调用“services.AddHttpContextAccessor()”来注册它的实例,则“IHttpContextAccessor”的实例将可供您使用 (2认同)

Ste*_*ger 29

Necromancing.
是的,你可以
为那些迁移大的人提供秘密提示帆船大块(叹息,弗洛伊德滑动)的代码.
下面的方法是一个黑客的邪恶痈,积极参与执行撒旦的快速工作(在.NET Core框架开发人员的眼中),但它的工作原理:

public class Startup

添加一个属性

public IConfigurationRoot Configuration { get; }
Run Code Online (Sandbox Code Playgroud)

然后在ConfigureServices中将单个IHttpContextAccessor添加到DI中.

    // 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>();
Run Code Online (Sandbox Code Playgroud)

然后在Configure中

    public void Configure(
              IApplicationBuilder app
             ,IHostingEnvironment env
             ,ILoggerFactory loggerFactory
    )
    {
Run Code Online (Sandbox Code Playgroud)

添加DI参数IServiceProvider svp,方法如下:

    public void Configure(
           IApplicationBuilder app
          ,IHostingEnvironment env
          ,ILoggerFactory loggerFactory
          ,IServiceProvider svp)
    {
Run Code Online (Sandbox Code Playgroud)

接下来,为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 


}
Run Code Online (Sandbox Code Playgroud)

现在在Configure中添加了IServiceProvider svp,将此服务提供者保存到刚创建的虚拟类System.Web.HttpContext(System.Web.HttpContext.ServiceProvider)中的静态变量"ServiceProvider"中

并将HostingEnvironment.IsHosted设置为true

System.Web.Hosting.HostingEnvironment.m_IsHosted = true;
Run Code Online (Sandbox Code Playgroud)

这基本上是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

    });
Run Code Online (Sandbox Code Playgroud)

就像在ASP.NET Web-Forms中一样,当你尝试访问HttpContext时,你会得到一个NullReference,例如它曾经Application_Start在global.asax中.

我再次强调,这只有在您真正添加时才有效

services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

就像我写的那样.
欢迎使用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;
            }
        }


    }


}
Run Code Online (Sandbox Code Playgroud)

然后在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>()
    );
Run Code Online (Sandbox Code Playgroud)

  • 这是纯粹的恶意 (31认同)
  • 我知道我们都必须尽力指出这是多么邪恶的恶魔...但是如果你将一个巨大的项目移植到Core,那么在一些难以触及的静态类中使用了HttpContext.Current.这可能非常有用.在那里,我说了. (6认同)
  • 具有帮助程序方法的版本是否在每个方案中正常工作.考虑多线程,异步和具有不同生命周期的IoC容器中的服务? (2认同)
  • 这是纯粹的邪恶......并且我将在万圣节实施它.我喜欢DI和IoC ......但是我正在处理一个带有邪恶静态变量的恶习静态变量的遗留应用程序,我们需要使用Kestrel推送并尝试注入HttpContext对我们来说是可以撤销的,而不会破坏所有内容. (2认同)
  • 是的,这是迁移的正确答案。;) (2认同)

khe*_*ang 21

只是为了添加其他答案......

在ASP.NET 2.1的核心,还有AddHttpContextAccessor扩展方法,将注册IHttpContextAccessor与正确的寿命.

  • 很高兴看到撒旦的更正式替代品! (2认同)

Jan*_*Jan 14

我提出的最合法的方法是在静态实现中注入IHttpContextAccessor,如下所示:

public static class HttpHelper
{
     private static IHttpContextAccessor _accessor;
     public static void Configure(IHttpContextAccessor httpContextAccessor)
     {
          _accessor = httpContextAccessor;
     }

     public static HttpContext HttpContext => _accessor.HttpContext;
}
Run Code Online (Sandbox Code Playgroud)

然后在启动配置中分配IHttpContextAccessor应该可以完成这项工作.

HttpHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
Run Code Online (Sandbox Code Playgroud)

我想你还应该注册服务单例:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
Run Code Online (Sandbox Code Playgroud)

  • 我想你可以直接在Startup.cs的ConfigureServices函数中使用`services.AddHttpContextAccessor();`,而不是真正需要`services.AddSingleton` (2认同)

Jah*_*han 8

根据这篇文章:在 ASP.NET Core 中的框架组件之外访问 HttpContext

namespace System.Web
{
    public static class HttpContext
    {
        private static IHttpContextAccessor _contextAccessor;

        public static Microsoft.AspNetCore.Http.HttpContext Current => _contextAccessor.HttpContext;

        internal static void Configure(IHttpContextAccessor contextAccessor)
        {
            _contextAccessor = contextAccessor;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

public static class StaticHttpContextExtensions
{
    public static void AddHttpContextAccessor(this IServiceCollection services)
    {
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    }

    public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
    {
        var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
        System.Web.HttpContext.Configure(httpContextAccessor);
        return app;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddHttpContextAccessor();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticHttpContext();
        app.UseMvc();
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以这样使用它:

using System.Web;

public class MyService
{
   public void DoWork()
   {
    var context = HttpContext.Current;
    // continue with context instance
   }
}
Run Code Online (Sandbox Code Playgroud)


小智 5

在启动

services.AddHttpContextAccessor();
Run Code Online (Sandbox Code Playgroud)

在控制器中

public class HomeController : Controller
    {
        private readonly IHttpContextAccessor _context;

        public HomeController(IHttpContextAccessor context)
        {
            _context = context; 
        }
        public IActionResult Index()
        {
           var context = _context.HttpContext.Request.Headers.ToList();
           return View();
        }
   }
Run Code Online (Sandbox Code Playgroud)

  • 这里没有足够的信息来知道下一步该做什么 (2认同)