ฉันต้องการเข้าถึงกระแสHttpContext
ในวิธีคงที่หรือบริการยูทิลิตี้
ด้วย ASP.NET MVC แบบคลาสสิกและSystem.Web
ฉันจะใช้HttpContext.Current
เพื่อเข้าถึงบริบทแบบคงที่ แต่ฉันจะทำสิ่งนี้ใน ASP.NET Core ได้อย่างไร?
ฉันต้องการเข้าถึงกระแสHttpContext
ในวิธีคงที่หรือบริการยูทิลิตี้
ด้วย ASP.NET MVC แบบคลาสสิกและSystem.Web
ฉันจะใช้HttpContext.Current
เพื่อเข้าถึงบริบทแบบคงที่ แต่ฉันจะทำสิ่งนี้ใน ASP.NET Core ได้อย่างไร?
คำตอบ:
HttpContext.Current
ไม่มีอยู่ใน ASP.NET Core อีกต่อไป แต่มีสิ่งใหม่ IHttpContextAccessor
ที่คุณสามารถฉีดในการอ้างอิงของคุณและใช้เพื่อดึงข้อมูลปัจจุบันHttpContext
:
public class MyComponent : IMyComponent
{
private readonly IHttpContextAccessor _contextAccessor;
public MyComponent(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public string GetDataFromSession()
{
return _contextAccessor.HttpContext.Session.GetString(*KEY*);
}
}
CallContextServiceLocator
ในการแก้ปัญหาการให้บริการแม้จะมาจากอินสแตนซ์ที่ไม่ใช่ CallContextServiceLocator.Locator.ServiceProvider.GetService<IHttpContextAccessor>()
DI-ฉีด: ในทางปฏิบัติมันเป็นสิ่งที่ดีถ้าคุณสามารถหลีกเลี่ยงได้ :)
Necromancing
ใช่คุณสามารถ
เคล็ดลับลับสำหรับผู้ที่ย้ายข้อมูลขนาดใหญ่เรือสำเภาชิ้นส่วน (ถอนหายใจสลิปฟรอยด์) ของรหัส
วิธีต่อไปนี้เป็น carbuncle ชั่วร้ายของการแฮ็กที่มีส่วนร่วมอย่างแข็งขันในการดำเนินการด่วนของซาตาน (ในสายตาของผู้พัฒนา. NET Core framework) แต่มันใช้ได้ผล :
ใน public class Startup
เพิ่มคุณสมบัติ
public IConfigurationRoot Configuration { get; }
จากนั้นเพิ่ม Singleton 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>();
จากนั้นในกำหนดค่า
public void Configure(
IApplicationBuilder app
,IHostingEnvironment env
,ILoggerFactory loggerFactory
)
{
เพิ่มพารามิเตอร์ DI IServiceProvider svp
ดังนั้นวิธีการจึงดูเหมือน:
public void Configure(
IApplicationBuilder app
,IHostingEnvironment env
,ILoggerFactory loggerFactory
,IServiceProvider svp)
{
จากนั้นสร้างคลาสทดแทนสำหรับ 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
}
ตอนนี้ใน Configure ที่คุณเพิ่มให้IServiceProvider svp
บันทึกผู้ให้บริการรายนี้ลงในตัวแปรคงที่ "ServiceProvider" ในคลาสจำลองที่เพิ่งสร้างขึ้น System.Web.HttpContext (System.Web.HttpContext.ServiceProvider)
และตั้งค่า HostingEnvironment.IsHosted เป็น true
System.Web.Hosting.HostingEnvironment.m_IsHosted = true;
นี่คือสิ่งที่ SystemWeb ทำโดยที่คุณไม่เคยเห็นมัน (ฉันเดาว่าตัวแปรถูกประกาศเป็นภายในแทนที่จะเป็นสาธารณะ)
// 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 Web-Forms คุณจะได้รับ NullReference เมื่อคุณพยายามเข้าถึง HttpContext เมื่อไม่มีเช่นเคยอยู่Application_Start
ใน global.asax
ฉันเครียดอีกครั้งสิ่งนี้ใช้ได้ผลก็ต่อเมื่อคุณเพิ่มเข้าไปจริงๆ
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.Configure ใน 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>()
);
วิธีที่ถูกต้องที่สุดที่ฉันคิดขึ้นคือการฉีด IHttpContextAccessor ในการใช้งานแบบคงที่ของคุณดังต่อไปนี้:
public static class HttpHelper
{
private static IHttpContextAccessor _accessor;
public static void Configure(IHttpContextAccessor httpContextAccessor)
{
_accessor = httpContextAccessor;
}
public static HttpContext HttpContext => _accessor.HttpContext;
}
จากนั้นกำหนด IHttpContextAccessor ใน Startup Configure ควรทำงาน
HttpHelper.Configure(app.ApplicationServices.GetRequiredService<IHttpContextAccessor>());
ฉันเดาว่าคุณควรจะต้องลงทะเบียนบริการ singleton:
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
เพียงเพื่อเพิ่มคำตอบอื่น ๆ ...
ใน ASP.NET 2.1 หลักมีวิธีขยายที่จะลงทะเบียนกับอายุการใช้งานที่ถูกต้อง:AddHttpContextAccessor
IHttpContextAccessor
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
// Other code...
}
อ้างอิงจากบทความนี้: การเข้าถึง HttpContext นอกส่วนประกอบของเฟรมเวิร์กใน ASP.NET Core
namespace System.Web
{
public static class HttpContext
{
private static IHttpContextAccessor _contextAccessor;
public static Microsoft.AspNetCore.Http.HttpContext Current => _contextAccessor.HttpContext;
internal static void Configure(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
}
}
แล้ว:
public static class StaticHttpContextExtensions
{
public static void AddHttpContextAccessor(this IServiceCollection services)
{
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
{
var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
System.Web.HttpContext.Configure(httpContextAccessor);
return app;
}
}
แล้ว:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpContextAccessor();
}
public void Configure(IApplicationBuilder app)
{
app.UseStaticHttpContext();
app.UseMvc();
}
}
คุณสามารถใช้งานได้ดังนี้:
using System.Web;
public class MyService
{
public void DoWork()
{
var context = HttpContext.Current;
// continue with context instance
}
}
ในการเริ่มต้น
services.AddHttpContextAccessor();
ในตัวควบคุม
public class HomeController : Controller
{
private readonly IHttpContextAccessor _context;
public HomeController(IHttpContextAccessor context)
{
_context = context;
}
public IActionResult Index()
{
var context = _context.HttpContext.Request.Headers.ToList();
return View();
}
}
IHttpContextAccessor
จะใช้ได้เฉพาะในสถานที่ที่คอนเทนเนอร์ DI กำลังแก้ไขอินสแตนซ์