Подтвердить что ты не робот

Доступ к текущему HttpContext в ядре ASP.NET

Мне нужно получить доступ к текущему HttpContext в статическом или служебном сервисе.

С классическим ASP.NET MVC и System.Web я просто использовал бы HttpContext.Current для доступа к контексту статически. Но как это сделать в ASP.NET Core?

4b9b3361

Ответ 1

HttpContext.Current больше не существует в ASP.NET Core, но есть новый IHttpContextAccessor который вы можете 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*);
    }
}

Ответ 2

Necromancing.

ДА ВЫ МОЖЕТЕ Секретный совет для тех, кто переносит большие куски (sigh, Freudian slip) кода.
Следующий метод - злой карбункул взлома, который активно участвует в выполнении экспресс-работы сатаны (в глазах разработчиков платформы .NET Core), , но работает:

В public class Startup

добавить свойство

public IConfigurationRoot Configuration { get; }

И затем добавьте singleton IHttpContextAccessor в DI в ConfigureServices.

    // 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>();

Затем в Configure

    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 


}

Теперь в Configure, где вы добавили IServiceProvider svp, сохраните этот поставщик услуг в статической переменной "ServiceProvider" только что созданного фиктивного класса System.Web.HttpContext(System.Web.HttpContext.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, вы получите NullReference, когда вы пытаетесь получить доступ к HttpContext, когда его нет, например, он использовался в Application_Start в global.asax.

Я снова подчеркиваю: это работает только если вы действительно добавили

services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();

как я написал, вы должны.

Добро пожаловать в шаблон ServiceLocator в шаблоне DI;)
Для рисков и побочных эффектов обратитесь к своему резидентному врачу или фармацевту или изучите источники .NET Core на github.com/aspnet и выполните некоторые тесты.


Возможно, более поддерживаемый метод будет добавлять этот вспомогательный класс

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;
            }
        }


    }


}

И затем вызовите HttpContext.Configure в Startup- > 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>()
    );

Ответ 4

Самый законный способ, с которым я столкнулся, заключался в том, чтобы вставлять IHttpContextAccessor в вашу статическую реализацию следующим образом:

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

     public static HttpContext HttpContext => _accessor.HttpContext;
}

Затем назначение IHttpContextAccessor в Startup Configure должно выполнять задание.

HttpHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());

Думаю, вам также нужно зарегистрировать службу singleton:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();

Ответ 5

Согласно этой статье: Доступ к HttpContext вне компонентов фреймворка в ASP.NET Core

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;
        }
    }
}

Затем:

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;
    }
}

Затем:

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

    public void Configure(IApplicationBuilder app)
    {
        app.UseStaticHttpContext();
        app.UseMvc();
    }
}

Вы можете использовать это так:

using System.Web;

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

Ответ 6

Как правило, преобразование приложения Web Forms или MVC5 в ASP.NET Core потребует значительного объема рефакторинга.

HttpContext.Current был удален в ASP.NET Core. Доступ к текущему HTTP-контексту из отдельной библиотеки классов - это тип грязной архитектуры, которую ASP.NET Core пытается избежать. Есть несколько способов перестроить это в ASP.NET Core.

Свойство HttpContext

Вы можете получить доступ к текущему HTTP-контексту через свойство HttpContext на любом контроллере. Самым близким к вашему исходному HttpContext кода будет передать 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 в промежуточном программном обеспечении

Если вы пишете пользовательское middleware для конвейера ASP.NET Core, текущий запрос HttpContext передается в ваш метод Invoke:

public Task Invoke(HttpContext context)
{
    // Do something with the current HTTP context...
}

Средство доступа к контексту HTTP

Наконец, вы можете использовать вспомогательную службу IHttpContextAccessor для получения HTTP-контекста в любом классе, который управляется системой внедрения зависимостей ASP.NET Core. Это полезно, когда у вас есть общая служба, используемая вашими контроллерами.

Запросите этот интерфейс в вашем конструкторе:

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

Затем вы можете получить доступ к текущему HTTP-контексту безопасным способом:

var context = _httpContextAccessor.HttpContext;

//Делаем что-то с current HTTP context... IHttpContextAccessor не всегда добавляется в контейнер службы по умолчанию, поэтому зарегистрируйте его в ConfigureServices просто для безопасности:

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

    // Other code...
}

Ответ 7

Просто добавьте это на всякий случай, если у кого-то есть какое-то огромное корпоративное приложение, которое они конвертируют в ядро .net, где везде присутствует HttpContext.Current, но если вы пытаетесь делать это статически и ищете способ подражать этому в .netcore Здесь это решение, но я не рекомендую делать это, если у вас тоже нет.

https://www.strathweb.com/2016/12/accessing-httpcontext-outside-of-framework-components-in-asp-net-core/

Ответ 8

В запуске

services.AddHttpContextAccessor();

В контроллере

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();
        }
   }