Comment obtenir HttpContext.Actuelle dans ASP.NET Core? [dupliquer]

cette question a déjà une réponse ici:

  • accéder au contexte Httpcontexte actuel ASP.NET Central 4 réponses

nous sommes en train de réécrire/convertir nos ASP.NET utilisation de L'application WebForms ASP.NET noyau. J'essaie d'éviter la réingénierie autant que possible.

il y a une section où nous utilisons HttpContext dans une bibliothèque de classe pour vérifier l'état actuel. Comment puis-je accéder à HttpContext.Current dans .NET Core 1.0?

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

j'ai besoin d'accéder à ceci pour construire l'hôte d'application actuel.

$"{current.Request.Url.Scheme}://{current.Request.Url.Host}{(current.Request.Url.Port == 80 ? "" : ":" + current.Request.Url.Port)}";
118
demandé sur abatishchev 2016-07-25 17:53:15

3 réponses

en règle générale, conversion d'un formulaire Web ou D'une application MVC5 en ASP.NET Core will require a significant amount of refactoring.

HttpContext.Current a été supprimé en ASP.NET noyau. Accéder au contexte HTTP actuel à partir d'une bibliothèque de classe séparée est le type d'architecture messy qui ASP.NET Core essaie d'éviter. Il y a plusieurs façons de re-concevoir ceci en ASP.NET noyau.

HttpContext property

vous pouvez accéder au contexte HTTP actuel via la propriété HttpContext sur n'importe quel contrôleur. La chose la plus proche de votre échantillon de code original serait de passer HttpContext dans la méthode que vous appelez:

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
}

paramètre HttpContext dans middleware

si vous écrivez middleware personnalisé pour le ASP.NET pipeline central, la demande actuelle HttpContext est passée dans votre méthode Invoke automatiquement:

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

accesseur de contexte HTTP

enfin, vous pouvez utiliser le service d'assistance IHttpContextAccessor pour obtenir le contexte HTTP dans n'importe quelle classe gérée par le ASP.NET système d'injection de la dépendance de base. Ceci est utile lorsque vous avez un service commun qui est utilisé par vos contrôleurs.

Demander cette interface dans votre constructeur:

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

vous pouvez alors accéder au courant Contexte HTTP D'une manière sûre:

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

IHttpContextAccessor n'est pas toujours ajouté au conteneur de service par défaut, donc enregistrez-le dans ConfigureServices juste pour être sûr:

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

    // Other code...
}
150
répondu Nate Barbettini 2018-04-25 18:42:28

Nécromancie.

OUI, VOUS POUVEZ, et c'est de cette façon.

Une astuce secrète pour les migrants de grande taille junks morceaux de code:

La méthode suivante est une carboncule diabolique d'un hack qui est activement engagé dans la réalisation de l'œuvre expresse de satan (aux yeux des développeurs de .net Core framework), mais il fonctionne :

Dans public class Startup

ajouter un bien

public IConfigurationRoot Configuration { get; }

et ensuite ajouter un seul IHttpContextAccessor à DI dans 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>();

puis dans Configure

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

ajouter le paramètre DI IServiceProvider svp , de sorte que la méthode ressemble à:

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

ensuite, créer une classe de remplacement pour le système.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 


}

MAINTENANT Dans Configure, où vous ajouté le IServiceProvider svp , enregistrer ce fournisseur de services dans la variable statique" ServiceProvider " dans le système de la classe mannequin juste créé.Web.HttpContext (System.Web.HttpContext.ServiceProvider)

et set HostingEnvironment.IsHosted to true

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

c'est essentiellement ce système.Web a fait, juste que vous ne l'avez jamais vu (je suppose que la variable a été déclarée comme interne au lieu de Publique).

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

    });

comme dans ASP.NET les formulaires Web, vous obtiendrez une référence nulle lorsque vous tentez d'accéder à un HttpContext alors qu'il n'y en a pas, comme dans Application_Start dans global.asax.

j'insiste encore, cela ne fonctionne que si vous avez réellement ajouté""

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

comme je vous l'ai écrit.

Bienvenue sur le ServiceLocator motif au sein de la DI ;)

Pour les risques et les effets secondaires, consultez votre médecin résident ou pharmacien - ou étudier les sources de .NET Core à github.com/aspnet , et faire quelques tests.


peut-être une méthode plus maintenable serait d'ajouter cette classe d'aide

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


    }


}

et ensuite appeler HttpContext.Configurer au démarrage - > configurer

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
répondu Stefan Steiger 2017-04-02 21:17:07

il y a une solution à cela si vous avez vraiment besoin d'un accès statique au contexte actuel. En Démarrage.Configurer.…()

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

et quand vous en avez besoin vous pouvez l'obtenir avec:

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

j'espère que ça aidera. Gardez à l'esprit Cette solution est lorsque vous n'avez pas le choix. La meilleure pratique consiste à utiliser l'injection de dépendances.

8
répondu HLS 2016-09-19 10:28:52