در این مقاله توضیحاتی را در خصوص نحوه پردازش یک درخواست در ASP.NET Core ارائه خواهم داد.
زمانی که یک درخواست توسط کاربر ایجاد میشود، ابتدا توسط یک وب سرور دریافت و به وب سرور داخلی NET Core یعنی Kestrel ارسال می شود، بعد از دریافت درخواست (http context) توسط Kestrel آن را در مسیر اجرا قرار میدهد، این فرایند پردازش را pipeline میگویند، pipeline دارای یک سری قطعات اجرایی هستند که بهصورت زنجیره ای به یکدیگر متصل شده اند، این قطعات را middleware میگویند. این قطعات دارای یک ورودی و یک خروجی هستند، بعد از دریافت Http context هر middleware آن را پردازش می کند و به Middleware بعدی ارسال میکند.
در نهایت یک قطعه نهایی به نام endpoint middleware وجود دارد که خروجی قطعه قبلی را دریافت و پردازش میکند، پس از پردازش نتیجه را به middleware قبلی ارسال میکند تا به قطعه اول برسد، سپس قطعه اول درخواست پردازش شده را به kestrel و به وب سرور و در نهایت به کاربر درخواست کننده ارسال میکند.
همانطور که در شکل بالا ملاحظه میکنید، زمانی که کاربر یک درخواست را ارسال میکند، در پشت زمینه یک نمونه از http context ایجاد می شود. http context شامل مقادیر متفاوتی از اطلاعات شامل http request و https response ،اطلاعات کاربر، session، و اطلاعات ارتباطی نیز می باشد. برای بررسی
هر درخواست http شامل سه قسمت می باشد، request line، request header و body. البته اطلاعات body می تواند خالی باشد.
اطلاعات request line
اطلاعات request header
شامل صفر یا چند header می باشد، از header ها برای ارسال اطلاعات بیشتر در مورد درخواست استفاده می شود. به عنوان مثال، نوع content-type که کاربر در خواست میدهد چه چیزی باید باشد.
اطلاعات request body
همانطور که اشاره کردم، این اطلاعات می توانند اختیاری باشند که به سرور ارسال می شوند. دلیل اختیاری بودن آن این است که فرض کنید شما یک سری اطلاعات را باید در پایگاه داده ثبت کنید، بدین منظور از طریق body آن اطلاعات را ارسال میکنید، اما در فرایند دیگر شما تنها نیازی دارید تا یک سری اطلاعات را واکشی و به کاربر نمایش دهید، بدین منظور نیازی به ارسال اطلاعات در body نمی باشد.
شامل اطلاعاتی است که پس از پردازش توسط سروربه کلاینت بازگردانده می شود، که شامل status line، response header و response body می باشد.
اطلاعات Status line
این اطلاعات شامل نسخه HTTP ، وضعیت کد، و status text می باشد.
اطلاعات response header
شامل یک یا چند response header است که برای ارسال اطلاعات اضافه از سمت client به server استفاده می شود.
اطاعات response body
شامل اطلاعاتی است که توسط کلاینت درخواست شده است، به عنوان مثال دریافت کاربر با کد ملی، دریافت اطلاعات یک کاربر با ایمیل و... اگر درخواست موفقیت آمیز نباشد، سپس response body شامل دلایل خطاهای بهوجود آمده خواهد بود.
اگر یک پروژه ASP.NET Core ایجاد کنیم، در فایل program.cs کدهای زیر را خواهیم دید:
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.MapGet("/", () => "Hello World!"); app.Run();
میتوان گفت فرایند اجرای برنامه به دو قسمت سرویس ها و pipeline تقسیم بندی می شوند، اولین فرایند، ثبت سرویس ها و وابستگی ها است که توسط webapplication builder ایجاد میشود بعد از اینکه آن را build میکنیم، یک application در اختیار داریم. که اجرای برنامه را در چرخه pipeline قرار خواهد داد.
یک وب سرور داخلی cross-platform در ASP.NET Core میباشد که در زمان توسعه NET Core. ایجاد می شود.
هر کلاس یک کار را انجام میدهد، مثلا سرویس repositoy که کار انجام تراکنش در DB را بر عهده دارد، یا کلاس Logger
طول عمر اشیا را بهasp.net core میسپاریم که به آن سرویس میگوییم.
var builder = WebApplication.CreateBuilder(args);
قطعه کد بالا نشان می دهد که در زمان اجرای برنامه ابتدا یک builder توسط CreateBuilder ایجاد میشود، همانطور که در بالا اشاره کردم، زمانی که یک پروژه ASP.NET Core ایجاد می کنیم، وب سرویس kestrel به صورت پیشفرض نیز داخل آن اجرا خواهد شد ،بدین صورت که بعد از اجرای دستور CreateBuilder ، این متد به صورت داخلی از UseKestrel استفاده می کند.
برای اینکه یک سرویس را در برنامه ثبت کنیم باید از builder.Services استفاده کنیم، به عنوان مثال برای فعال کردن احراز هویت باید از دستور زیر استفاده کنیم.
builder.Services.AddAuthentication()
بعد از اینکه تمامی سرویس های خود را ثبت کردیم نوبت به buildکردن آن و قرار دادن آنها در چرخه pipeline میباشد.
var app = builder.Build();
پایپلاین با چند middleware ساخته می شود، در اصل pipeline یک مسیر است، اما middleware بخش اجرایی از برنامه است.
برای پیادهسازیmiddleware از app.use استفاده میکنیم، که دارای دو پارامتر ورودی است، اولین ورودی آن http context است و ورودی دوم آن middleware بعدی است که قرار است اجرا شود.
app.Use(async (httpContext,next)=> { //middlware logics });
همانطور که قبلا توضیح دادم، middleware ها بهصورت زنجیره ای به هم متصل هستند، برای اینکه مشخص کنیم کدام قطعه قرار است در pipeline اجرا شود از next استفاده میکنیم.
استفاده از UseMiddleware
اگر به کد بالا بازگردیم، درمیابیم که برای ایجاد کردن middleware در program.cs نیاز است تا شاید صدها خط کد داخل آن بنویسیم، اما روش دیگری نیز وجود دارد که میتوان منطق middleware را به آن محول کرد و کدهای خود را در آن قسمت توسعه داد، بدین منظور میتوان از UseMiddleware استفاده کرد.
برای ایجاد یک middleware ابتدا نیاز داریم یک کلاس بهصورت زیر ایجاد کنیم، این کلاس باید چندین ویژگی داشته باشد.
public class ClassMiddleware { private readonly RequestDelegate _next; public ClassMiddleware (RequestDelegate next)=>_next=next; public async Task Invoke(HttpContext context) { // logic code omited for brevity await _next.Invoke(context); } }
و برای استفاده از این middleware باید در program.cs خود از دستور UseMiddleware بهصورت زیر استفاده کنیم.
app.UseMiddleware<ClassMiddleware>()
تمامی دستوراتی که در بالا نوشتیم از ثبت سرویس ها، ثبت وابستگی ها تا ایجاد middlewareها و قرار دادن آنها در مسیر pipeline تنها ثبت و ایجاد آنها بود، اما برای اجرای آنها باید از ()app.Run استفاده کنیم.
زمانی که app.run را اجرا میکنیم، تعدای hosted service اجرا میشوند، که به صورت long running task است.این task ها زمانی که باز می شوند، به چرخه ی اجرای خود ادامه میدهند، اما بر خلاف آن پروژه های Console application زمانی که به خط انتهایی می رسند چرخه عمر آنها نیز پایان میپذیرد.
میتوان گفت یک پروژه ASP.NET Core یک console applicaion بی انتها میباشد.
در این مقاله آموختیم که فرایند درخواست به چه صورتی پردازش میشوند، با مفاهیم http context، http، سرویس ها، middleware و pipeline آشنا شدیم.
دریافتیم که kestrel چیست و به چه منظوری مورد استفاده قرار میگیرد.
ممنونم بابت لایک، کامنت و دنبال کردن من، باعث میشه با قدرت بیشتری ادامه بدم :)