در این مقاله به بررسی استفاده از HttpContext خارج از یک MVC Controller در .Net Core 2.1 میپردازیم. هنگام کار بر روی یک برنامه ی وب مبتنی بر ASP.Net Core 2.1، با سناریویی روبرو شدم که باید تعدادی داده را داخل حافظه قرار میدادم. با این حال که این یک مشکل نیست، چیزی که درمییابیم این است که داده برای هر HTTP Session (نشست http) باید منحصر به فرد باشد.
این را به عنوان نگهداری یک کلید که برای استفاده در بین نماهای مختلف برای نمایش اطلاعات مربوط به آن جلسه ی خاص است در نظر بگیرید.
تنها راه حل ممکن که پاسخگوی نیازهای من بود، نگهداری “کلید” در جلسه بود. با این حال، آخرین نقطه در کد که به کلید دسترسی دارد یک کلاس کمکی ساده است و نه یک MVC Controller و که هیچ قصدی از نمایش “کلید” به کنترل کننده مان نداشتیم. بنابراین، این پرسش باقی میماند: چگونه کلید را در جلسه بدون نمایش آن به کنترل کننده ذخیره کنیم؟
نمونه کد جهت کار با HttpContext
در کدی که در ادامه می آید، یک برنامه ی MVC بسیار ساده و پایه با HomeController خود داریم. ما همچنین یک RequestHandler داریم که مراقب تمام منطق پشت زمینه است تا کنترل کننده مان را تمیز و سبک کند.
using HttpContextProject.Helpers; using HttpContextProject.Models; using Microsoft.AspNetCore.Mvc; using System.Diagnostics; namespace HttpContextProject.Controllers { public class HomeController : Controller { public IActionResult Index() { return View(); } public IActionResult About() { // handle the request and do something var requestHandler = new RequestHandler(); requestHandler.HandleAboutRequest(); ViewData["Message"] = "This is our default message for About Page!"; return View(); } } } namespace HttpContextProject.Helpers { public class RequestHandler { internal void HandleAboutRequest() { // do something here } } }
همانطور که در کد بالا دیده میشود، داریم به سادگی یک پیام را در ViewData تنظیم و روی نما تفسیر میکنیم. تا به حال اتفاق خاصی در کار نیست. حال، بیایید ببینیم چگونه میتوانیم پیام خود را در Http Session از RequestHandler تنظیم کنیم و بعدتر در داخل کنترل کننده به آن دسترسی پیدا کنیم.
استفاده از HttpContext در یک کلاس کمکی
با .Net Core 2.1 نمیتوانیم به HttpContext خارج از یک کنترل کننده دسترسی پیدا کنیم، با این حال، میتوانیم از IHttpContextAccessor برای دسترسی به نشست فعلی خارج از یک کنترل کننده استفاده کنیم.
برای انجام این کار، لازم است Session و میان-افزار HttpContextAccessor را به متد ConfigureServices از کلاس Startup خود همانطور که در کد زیر نشان داده شده اضافه کنیم.
using HttpContextProject.Helpers; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace HttpContextProject { public class Startup { public IConfiguration Configuration { get; } public Startup(IConfiguration configuration) { Configuration = configuration; } public void ConfigureServices(IServiceCollection services) { services.Configure<CookiePolicyOptions>(options => { options.CheckConsentNeeded = context => true; options.MinimumSameSitePolicy = SameSiteMode.None; }); services.AddSession(); services.AddSingleton<RequestHandler>(); services.AddHttpContextAccessor(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); } app.UseSession(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); }); } } }
کار بعدی که باید انجام دهیم افزودن یک وابستگی از IHttpContextAccessor در RequestHandler است. این کار به ما اجازه میدهد تا به HttpContext در داخل request handler (گرداننده ی درخواست) دسترسی پیدا کنیم. پس از اینکه پردازش مورد نیاز برای درخواست را انجام دادیم، حال میتوانیم پیام را، با استفاده از متد Session.SetString(key, value)، در نشست تنظیم کنیم. لطفا به کد زیر مراجعه کنید.
using Microsoft.AspNetCore.Http; namespace HttpContextProject.Helpers { public class RequestHandler { IHttpContextAccessor _httpContextAccessor; public RequestHandler(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } internal void HandleAboutRequest() { // handle the request var message = "The HttpContextAccessor seems to be working!!"; _httpContextAccessor.HttpContext.Session.SetString("message", message); } } }
حال که RequestHandler خود را بصورت کاملا تنظیم شده داریم، زمان این است که تغییراتی در HomeController ایجاد کنیم. هم اکنون، RequestHandler “جدید” در داخل متد عمل (action) قرار دارد، که این عمل خوبی نیست.
بنابراین، گرداننده را از کنترل کننده جدا کرده و ترجیحاً آن را به عنوان یک وابستگی در سازنده تزریق خواهم کرد. کار بعدی که انجام میدهیم این است که پیام را در ViewData از نشست تنظیم کنیم، همانطور که در کد زیر نشان داده شده است.
using HttpContextProject.Helpers; using HttpContextProject.Models; using Microsoft.AspNetCore.Mvc; using System.Diagnostics; namespace HttpContextProject.Controllers { public class HomeController : Controller { private readonly RequestHandler _requestHandler; public HomeController(RequestHandler requestHandler) { _requestHandler = requestHandler; } public IActionResult About() { _requestHandler.HandleAboutRequest(); ViewData["Message"] = HttpContext.Session.GetStringValue("message"); return View(); } } }
دقت داشته باشید که من از Session.GetStringValue(key) استفاده میکنم که یک متد افزودنی است که برای گرفتن داده ها از نشست اضافه کرده ام، با این حال، خیلی به آن نیازی نیست. میتوانید به سادگی از Session.TryGetValue(key, value) نیز استفاده کنید.
در صورتی که هنوز متوجه آن نشده اید، باید به شما بگویم که نیاز است RequestHandler خود را در متد ConfigureServices از کلاس Startup ثبت کنیم تا وابستگی برای کنترل کننده مان بتواند حل شود.
خلاصه
با تغییرات بالا در جایگاه، حالا میتوانیم به HttpContext.Session در گرداننده ی درخواست خود دسترسی پیدا کنیم و مشابه آن میتواند برای هر کلاس دیگری نیز انجام شود. با این حال، یک مورد است که در رابطه با این رویکرد دوست ندارم.
برای هر کدام از اجزا که نیاز است در آنجا به نشست دسترسی پیدا کنیم، باید یک وابستگی از IHttpContextAccessor تزریق کنیم.در حالیکه برای یک یا دو جزء مشکلی نیست، میتواند بسیار وحشتناک باشد اگر قرار باشد همین کار را بارها و بارها انجام دهیم.روشی برای دستیابی به همان قابلیت دسترسی بدون نیاز به تزریق هرگونه وابستگی وجود دارد.که در مقالات بعدی به این موضوع اشاره خواهیم داشت.
ای کاش بیشتر و بهتر میگفتین به نظر کار جالبی است
۱۰
حتما در این مورد مطالب بیشتری منتشر خواهد شد.
۷