Как получить HttpContext.Ток внутри ASP.NET ядро? [дубликат]



этот вопрос уже есть ответ здесь:



в настоящее время мы переписываем / преобразуем наши ASP.NET использование приложения WebForms ASP.NET ядро. Стараясь избежать реинжиниринга как можно больше.



есть раздел, где мы используем HttpContext в библиотеке классов для проверки текущего состояния. Как я могу получить доступ HttpContext.Current в .NET Core 1.0?



 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)}";
1498   3  

3 ответов:

как правило, преобразование веб-форм или приложения MVC5 в ASP.NET ядро потребуется значительное количество рефакторинга.

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

свойство HttpContext

вы можете получить доступ к текущему HTTP контекст через 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

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

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

http context accessor

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

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

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.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    // Other code...
}

некромантии.
Да, вы можете, и вот как.
Секретный совет для тех, кто мигрирует большой джонки куски кода:
Следующий метод-это злой карбункул взлома, который активно занимается проведением экспрессной работы Сатаны (в глазах разработчиков .NET Core framework),но он работает:

на public class Startup

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

public IConfigurationRoot Configuration { get; }

а затем добавить синглтон 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.Веб-сайт:

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" в только что созданной фиктивной системе классов.Сеть.HttpContext (Система.Сеть.HttpContext.Поставщику услуги)

и установите HostingEnvironment.Размещение в true

System.Web.Hosting.HostingEnvironment.m_IsHosted = true;

это по сути системы.Веб сделал, только что вы никогда не видели его (я думаю, переменная была объявлена как внутренняя, а не публичная).

// 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 веб-формы, вы получите NullReference, когда вы пытаетесь получить доступ к HttpContext, когда его нет, например, как это было в Application_Start в глобальном.асакс.

я подчеркиваю опять же, это работает только если вы на самом деле добавил

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.Настройка при запуске- > настроить

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

есть решение для этого, если вам действительно нужен статический доступ к текущему контексту. В Стартапе.Формировать.…()

app.Use(async (httpContext, next) =>
{
    CallContext.LogicalSetData("CurrentContextKey", httpContext);
    try
    {
        await next();
    }
    finally
    {
        CallContext.FreeNamedDataSlot("CurrentContextKey");
    }
});

и когда вам это нужно, вы можете сделать это с :

HttpContext context = CallContext.LogicalGetData("CurrentContextKey") as HttpContext;

Я надеюсь, что помогает. Имейте в виду этот способ, когда у вас нет выбора. Лучше всего использовать инъекцию зависимости de.

Comments

    Ничего не найдено.