2015-07-06 17 views

Odpowiedz

75

HttpContext.Current już nie istnieje w ASP.NET Rdzenia ale nowe IHttpContextAccessor że można wstrzyknąć w swoich zależnościach i używać do pobierania prądu HttpContext:

public class MyComponent : IMyComponent 
{ 
    private readonly IHttpContextAccessor _contextAccessor; 

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

    public string GetDataFromSession() 
    { 
     return _contextAccessor.HttpContext.Session.GetString(*KEY*); 
    } 
} 
+3

Dobra uwaga! Warto również wspomnieć, że 'IHttpContextAccessor' będzie dostępny tylko w miejscach, w których kontener DI rozpoznaje instancję. – tugberk

+4

@tugberk również, teoretycznie można również użyć 'CallContextServiceLocator' do rozwiązania usługi, nawet z instancji nie wstrzykniętej DI:' CallContextServiceLocator.Locator.ServiceProvider.GetService () '. W praktyce jest świetną rzeczą, jeśli możesz tego uniknąć :) – Pinpoint

+0

Proszę nie zamieszczać identycznych odpowiedzi na wiele pytań. Napisz jedną dobrą odpowiedź, a następnie głosuj/oznacz, aby zamknąć pozostałe pytania jako duplikaty. Jeśli pytanie nie jest duplikatem, * dostosuj swoje odpowiedzi na pytanie *. –

11

Necromancing.
TAK MOŻESZ
Sekretna wskazówka dla migrujących dużych dżunlików kawałków (westchnienie, poślizg Freuda) kodu.
Poniższa metoda jest zła carbuncle hack który jest aktywnie zaangażowany w przeprowadzenie wyraźnej dzieło szatana (w oczach programistów .NET Framework rdzenia), ale działa:

W public class Startup

dodać obiekt

public IConfigurationRoot Configuration { get; } 

a następnie dodać pojedyncza 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 Configure

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

dodać DI Parametr IServiceProvider svp, więc metoda wygląda następująco:

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

Następnie należy utworzyć klasę zastępczą dla 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 


} 

Teraz w programie Configure, gdzie dodano IServiceProvider svp, zapisz tego dostawcę usług do zmiennej statycznej "ServiceProvider" w właśnie utworzonej klasie dummy System.Web.HttpContext (System.Web.HttpContext.ServiceProvider)

i ustaw HostingEnvironment. IsHosted do prawdziwej

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

to zasadniczo co system.Web zrobił, tylko że nigdy nie widział go (chyba zmienna została zadeklarowana jako wewnętrzny zamiast publicznie).

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

    }); 

Podobnie jak w ASP.NET Web-Forms, dostaniesz NullReference kiedy próbujesz uzyskać dostęp do HttpContext gdy nie ma nikogo, tak jak kiedyś w Application_Start w global.asax.

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

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

jak pisałem powinieneś.
Witamy na wzorzec ServiceLocator w schemacie DI;)
W celu uzyskania informacji o zagrożeniach i działaniach niepożądanych należy zwrócić się do lekarza lub farmaceuty lub przeanalizować źródła .NET Core pod numerem github.com/aspnet i wykonać kilka testów.


Może to metoda bardziej linkujących będzie dodanie tej klasy pomocnika

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.Configure w Startup-> Konfiguracja

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

TO JEST PURE EVIL – Art

+1

Czy wersja z metodą pomocnika działa poprawnie w każdym scenariuszu. Myślenie o wielowątkowości, asynchronizacji i usługach w kontenerze IoC o różnym czasie życia? – manipurea

+2

Wiem, że wszyscy musimy zrobić wszystko, aby wskazać, jak diabelnie diabelnie jest to ... Ale jeśli przenosisz ogromny projekt do Core, gdzie HttpContext.Current został użyty w niektórych trudnodostępnych statycznych klasach. .. Prawdopodobnie byłoby to całkiem przydatne. Tam, powiedziałem to. –

2

najbardziej legit sposób wymyśliłem za pomocą wstrzyknięcia IHttpContextAccessor w statycznej implementacji w następujący sposób:

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

    public static HttpContext HttpContext => _accessor.HttpContext; 
} 

Następnie przypisanie IHttpContextAccessor w konfiguracji uruchamiania powinno wykonać zadanie.

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

Chyba powinno być konieczne, aby zarejestrować pojedyncza usługa:

services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 
+0

To działa dla mnie. – maztt

Powiązane problemy