Jak uzyskać HttpContext.Prąd w ASP.NET Rdzeń? [duplikat]

To pytanie ma już odpowiedź tutaj:

Obecnie przepisujemy / konwertujemy nasze ASP.NET aplikacja WebForms przy użyciu ASP.NET Rdzeń. Staram się unikać przeróbek jak najwięcej.

Jest sekcja, w której używamy HttpContext w bibliotece klas, aby sprawdzić bieżący stan. Jak Mogę uzyskać dostęp HttpContext.Current w. NET Core 1.0?

 var current = HttpContext.Current;
     if (current == null)
      {
       // do something here
       // string connection = Configuration.GetConnectionString("MyDb");
      }

Muszę uzyskać dostęp do tego, aby zbudować obecny host aplikacji.

$"{current.Request.Url.Scheme}://{current.Request.Url.Host}{(current.Request.Url.Port == 80 ? "" : ":" + current.Request.Url.Port)}";
Author: abatishchev, 2016-07-25

3 answers

Ogólnie rzecz biorąc, konwersja formularzy internetowych lub aplikacji MVC5 na ASP.NET Rdzeń będzie wymagał znacznej ilości refaktoryzacji.

HttpContext.Current został usunięty w ASP.NET Rdzeń. Dostęp do bieżącego kontekstu HTTP z oddzielnej biblioteki klas jest typem architektury, która ASP.NET Core stara się unikać. Istnieje kilka sposobów na ponowne zaprojektowanie tego w ASP.NET Rdzeń.

Właściwość HttpContext

Możesz uzyskać dostęp do bieżącego kontekstu HTTP za pomocą właściwości HttpContext na dowolnym kontrolerze. Najbliższą rzeczą do oryginalnej próbki kodu byłoby przekazanie HttpContext do metody, którą wywołujesz:

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
}

Parametr HttpContext w middleware

Jeśli piszesz custom middleware dla ASP.NET Core pipeline, bieżące żądanie {[6] } jest przekazywane do twojej metody Invoke automatycznie:

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

HTTP context accessor

Wreszcie, możesz użyć usługi helper IHttpContextAccessor, aby uzyskać kontekst HTTP w dowolnej klasie, która jest zarządzane przez ASP.NET Core dependency injection system. Jest to przydatne, gdy masz wspólną usługę używaną przez kontrolery.

Poproś o ten interfejs w konstruktorze:

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

Możesz wtedy uzyskać dostęp do bieżącego kontekstu HTTP w bezpieczny sposób:

var context = _httpContextAccessor.HttpContext;
// Do something with the current HTTP context...

IHttpContextAccessor nie zawsze jest domyślnie dodawany do kontenera usługi, więc zarejestruj go w ConfigureServices dla bezpieczeństwa:

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

    // Other code...
}
 150
Author: Nate Barbettini,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 18:42:28

Nekromancja.
Tak, możesz, i to jest jak.
Tajna wskazówka dla migrujących dużych junksów fragmentów kodu:
Poniższa metoda jest złym przykładem hakera, który aktywnie angażuje się w ekspresowe dzieło szatana (w oczach twórców. NET Core framework), ale działa [21]}: {]}

W public class Startup

Dodaj nieruchomość

public IConfigurationRoot Configuration { get; }

A następnie dodać singleton IHttpContextAccessor do DI w 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>();

Następnie w konfiguracji

    public void Configure(
              IApplicationBuilder app
             ,IHostingEnvironment env
             ,ILoggerFactory loggerFactory
    )
    {

Dodaj parametr DI IServiceProvider svp, Aby metoda wyglądała następująco:

    public void Configure(
           IApplicationBuilder app
          ,IHostingEnvironment env
          ,ILoggerFactory loggerFactory
          ,IServiceProvider svp)
    {

Następnie utwórz klasę zastępczą dla systemu.Www:

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 


}

Teraz w Configure, gdzie Dodano IServiceProvider svp, Zapisz tego dostawcę usług do zmiennej statycznej "ServiceProvider" w właśnie utworzonym systemie klas dummy.Www.HttpContext (System.Www.HttpContext.ServiceProvider)

I ustawić środowisko gospodarza.IsHosted to true

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

To jest w zasadzie jaki System.Web zrobił, tylko, że nigdy go nie widziałem(myślę, że zmienna została zadeklarowana jako wewnętrzna zamiast publicznej).

// 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

    });

Jak w ASP.NET Web-Forms, otrzymasz NullReference, gdy próbujesz uzyskać dostęp do HttpContext, gdy nie ma go, takiego jak kiedyś w Application_Start W global.asax.

Podkreślam ponownie, to działa tylko wtedy, gdy rzeczywiście dodał

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

Tak jak napisałem powinieneś.
Witamy w ServiceLocator Wzór W di wzór ;)
Aby dowiedzieć się więcej o zagrożeniach i skutkach ubocznych, skontaktuj się z lekarzem rezydentem lub farmaceutą - lub zbadaj źródła. NET Core pod adresem github.com/aspnet , i zrobić kilka testów.


Być może bardziej łatwą do utrzymania metodą byłoby dodanie tej klasy pomocniczej

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


    }


}

, a następnie wywołanie HttpContext.Konfiguracja w 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>()
    );
 29
Author: Stefan Steiger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-04-02 21:17:07

Jest na to rozwiązanie, jeśli naprawdę potrzebujesz statycznego dostępu do bieżącego kontekstu. W Startupie.Konfiguracja ( ... ))

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

A kiedy go potrzebujesz, możesz go dostać za pomocą:

HttpContext context = CallContext.LogicalGetData("CurrentContextKey") as HttpContext;
Mam nadzieję, że to pomoże. Pamiętaj, że to obejście ma miejsce wtedy, gdy nie masz wyboru. Najlepszą praktyką jest stosowanie de dependency injection.
 8
Author: HLS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-09-19 10:28:52