Nous sommes en train de réécrire/convertir notre application ASP.NET WebForms à l'aide d'ASP.NET Core. Essayer d'éviter la réingénierie autant que possible.
Il y a une section où nous utilisons HttpContext
dans une bibliothèque de classes pour vérifier l'état actuel. Comment accéder à HttpContext.Current
dans .NET Core 1.0?
var current = HttpContext.Current;
if (current == null)
{
// do something here
// string connection = Configuration.GetConnectionString("MyDb");
}
Je dois accéder à cela afin de construire l'application hôte actuelle.
$"{current.Request.Url.Scheme}://{current.Request.Url.Host}{(current.Request.Url.Port == 80 ? "" : ":" + current.Request.Url.Port)}";
En règle générale, la conversion d'une application Web Forms ou MVC5 en ASP.NET Core nécessite une quantité importante de refactoring.
HttpContext.Current
a été supprimé de ASP.NET Core. L'accès au contexte HTTP actuel à partir d'une bibliothèque de classes distincte est le type d'architecture désordonnée qu'ASP.NET Core tente d'éviter. Il existe plusieurs façons de réorganiser cela dans ASP.NET Core.
Vous pouvez accéder au contexte HTTP actuel via la propriété HttpContext
de tout contrôleur. La chose la plus proche de votre exemple 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
}
Si vous écrivez middleware personnalisé pour le pipeline ASP.NET Core, le HttpContext
de la requête en cours est automatiquement transmis à votre méthode Invoke
:
public Task Invoke(HttpContext context)
{
// Do something with the current HTTP context...
}
Enfin, vous pouvez utiliser le service d'assistance IHttpContextAccessor
pour obtenir le contexte HTTP de toute classe gérée par le système d'injection de dépendances ASP.NET Core. Ceci est utile lorsque vous avez un service commun utilisé par vos contrôleurs.
Demander cette interface dans votre constructeur:
public MyMiddleware(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
Vous pouvez ensuite accéder au contexte HTTP actuel de manière sécurisée:
var context = _httpContextAccessor.HttpContext;
// Do something with the current HTTP context...
IHttpContextAccessor
n'est pas toujours ajouté au conteneur de services par défaut. Enregistrez-le donc dans ConfigureServices
juste pour être sûr:
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
// if < .NET Core 2.2 use this
//services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Other code...
}
Nécromancie.
OUI VOUS POUVEZ, et voici comment.
Un secret pour les grands migrants jonques morceaux de code:
La méthode suivante est un mauvais plan d’un hack qui est activement engagé dans le travail express de satan (aux yeux des développeurs du framework .NET Core), , mais il travaux :
Dans public class Startup
ajouter une propriété
public IConfigurationRoot Configuration { get; }
Et puis ajoutez un singleton 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
)
{
ajoutez le paramètre DI IServiceProvider svp
, de sorte que la méthode se présente comme suit:
public void Configure(
IApplicationBuilder app
,IHostingEnvironment env
,ILoggerFactory loggerFactory
,IServiceProvider svp)
{
Ensuite, créez une classe de remplacement pour 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
}
Maintenant, dans Configure, où vous avez ajouté le IServiceProvider svp
, enregistrez ce fournisseur de services dans la variable statique "ServiceProvider" de la classe factice System.Web.HttpContext créée (System.Web.HttpContext.ServiceProvider).
et définissez HostingEnvironment.IsHosted sur true
System.Web.Hosting.HostingEnvironment.m_IsHosted = true;
c'est essentiellement ce que System.Web a fait, mais vous ne l'avez jamais vu (je suppose que la variable a été déclarée comme étant interne plutôt que 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 les formulaires Web ASP.NET, vous obtenez un NullReference lorsque vous essayez d'accéder à un HttpContext lorsqu'il n'y en a aucun, tel qu'il était auparavant dans Application_Start
dans global.asax.
Je souligne encore, cela ne fonctionne que si vous avez réellement ajouté
services.AddSingleton<Microsoft.AspNetCore.Http.IHttpContextAccessor, Microsoft.AspNetCore.Http.HttpContextAccessor>();
comme je l'ai écrit, vous devriez.
Bienvenue dans le modèle ServiceLocator dans le modèle DI;)
Pour les risques et les effets secondaires, demandez à votre médecin ou à votre pharmacien - ou étudiez les sources de .NET Core à github.com/aspnet , et effectuez des tests.
Peut-être une méthode plus maintenable serait-elle 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 puis en appelant HttpContext.Configure dans 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>()
);
Il existe une solution à cela si vous avez vraiment besoin d'un accès statique au contexte actuel. Dans Startup.Configure (….)
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 aide. N'oubliez pas que cette solution de contournement se produit lorsque vous n'avez pas le choix. La meilleure pratique consiste à utiliser l'injection de dépendance.