میان افزارها کدهایی هستند که بر روی درخواست های ورودی و پاسخ های بیرونی کنترل دارند و آنها را اداره می کنند. ASP.NET Core MVC 3 همراه خود برخی از کاربردهای کنترل بر روی درخواست ها و پاسخ ها را به گونه متدهایی پیاده سازی و فراهم کرده است ولی پیش خواهد آمد که شما بخواهید میان افزارهای ویژه و دلخواه خودتان را بنویسید.

نوشتن میان افزار دلخواه

میان افزارها درون کلاس ها کپسوله می شوند و به کمک Extension Method ها در دسترس قرار می گیرن. برای نوشتن میان افزار از سه متد ()Use و ()Invoke و ()Run کمک گرفته می شود. در کنار اینکه می توانیم کلاس های جداگانه را برای نوشتن میان افزار به کار ببریم، می توانیم از توابع بی نام (Anonymous Method) نیز کمک بگیریم. اگر برای نوشتن میان افزارها متدهای بی نام به کار روند، آن را In-Line Middleware و اگر از کلاس ها کمک گرفته شود، پس آن را On-Line Middleware گویند.

هر میان افزار درون Request Pipeline به جز اینکه روی درخواست های ورودی و پاسخ های برگشتی HTTP نظارت دارد، باید میان افزار پَسین (بعدی) را نیز فراخوانی (Invoke) کند. هر میان افزار عملیات هایی را پیش از و پس از یک میان افزار دیگر (میان افزار پَسین خود) انجام می دهد.

متد ()Run از اینتفریس IApplicationBuilder یک میان افزار نهایی را به Request Pipeline برنامه می افزاید. همانگونه که گفتیم میان افزارها در متد ()Configure از کلاس Startup افزوده می شوند و از این رو در متد ()Configure زیر، تنها یک بار متد ()Run به کمک متغیر app از نوع IApplicationBuilder فراخوانی شده است.

در کد زیر یک تابع بی نام و به کمک ویژگی های برنامه نویسی ناهمگام (Async) میان افزاری نوشته شده که بر روی همه درخواست ها اعمال می شود. context در کد زیر نمونه ای از کلاس HttpContext است و از این رو به کمک Response می توانیم به گونه ناهمگام و به کمک ()WriteAsync، نوشته ای را بر روی بدنه پاسخ چاپ می کنیم. تنها چیزی که نباید فراموش کنید این است که برای به کار بردن متد ()Response.WriteAsync باید فضای نام Microsoft.AspNetCore.Http بالای برنامه افزوده شود.

درباره کد بالا باید گفت که تک میان افزاری نوشته شده که بر روی همه درخواست ها یک رشته را چاپ می کند. به گفته بهتر هر درخواستی که از هر نشانی URL شناخته شده ای بیاید، همین رشته نمایش داده می شود. برای نمونه من نشانی localhost:5001/Home/Privacy را به کار برده ام ولی اگر شما نشانی localhost:5001/index را نیز به کار ببرید همین رشته نشان داده می شود.

نوشتن چندین میان افزار دلخواه

در کد و نمونه بالا تنها یک میان افزار در ()Configure نوشته شده است که بر همه درخواست های ورودی نظارت دارد. در کدهای زیر دوبار ()app.Run نوشته شده است و از این رو باید دو میان افزار داشته باشیم ولی در واقع تنها نخستین ()app.Run انجام می شود. توجه کنید ()Run متدی است که میان افزار نهایی (Terminal Middleware) را به برنامه می افزاید.

اگر بخواهیم چندین میان افزار داشته باشیم، پس باید یکی پس از دیگری به کمک متد ()Invoke فراخوانی شوند. کد زیر الگوی نوشتن چندین میان افزار به کمک ()Run را نشان می دهد. توضیح هایی که پیش و پس از ()next.Invoke نوشته شده اند نشان می دهد که می توان پیش از یا پس از فراخوانی میان افزار پَسین (بعدی)، یک سری کارها را انجام داد.

در کد زیر به کمک دو بر فراخوانی متد ()Use و یک بار فراخوانی ()Run سه میان افزار را نوشته ایم که بر پایه شکل زیر، در هر کدام، یک نوشته نشان داده می شود. توجه کنید در دو میان افزار نخستین، متد ()Invoke به کمک پارامتر next در تابع به نام فرستاده شده به ()Run فراخوانی می شود تا از این رو، هر یک، میان افزار پَسین خود را فراخوانی کند.

در واپسین (آخرین) کد اگر در دومین متد ()Use دستور ()next.Invoke را پاک کنیم، پس بر پایه شکل زیر، دیگر سومین میان افزار انجام نمی شود، زیرا در اینجا دومین متد ()Use پایان Request Pipeline برنامه را نشان می دهد. توجه کنید context از نوع کلاس HttpContext و next یک تابع Delegate از نوع Task به گونه <Func<Task است و نیازی نیست که حتما از نام های context و next استفاده کنید بلکه می توانید هر نام دیگری را به کار ببرید.

چکیده

  • تابع بی نام نوشته شده درون متد ()Use دارای دو پارامتر ورودی است، که نخستین آن از نوع کلاس HttpContext و دومین یک تابع Delegate به گونه <Func<Task است.
  • در متد ()Use آنچه که پیش از ()await next.Invoke این نوشته می شود، کارهایی (کدهایی) است که با ورود به میان افزار کنونی انجام می شوند و کدهایی که پس از ()await next.Invoke با بیرون آمدن از میان افزار کنونی انجام می شوند. در این باره در نوشتع پیش رو گفته ایم.
  • در متد ()Use دستور ()await next.Invoke یعنی میان افزار پَسین (بعدی) در Request Pipeline فراخوانی شود.
  • تابع بی نام نوشته شده درون متد ()Run دارای تک پارامتر ورودی از نوع کلاس HttpContext است.
  • HttpContext کلاسی است که داده هایی درباره درخواست فراهم می کند. برای نمونه می خواهیم مسیر (Path) درخواست یا رشته کوئری فرستاده شده در نشانی URL را بدانیم. درباره کلاس HttpContext و کاربرد آن در میان افزار در نوشته نوشتن میان افزار دلخواه در ASP.NET Core MVC بخش دوم و کلاس HttpContext گفته ایم.
  • توجه کنید بر پایه آنچه که در نوشته مفهوم مسیرها در ASP.NET Core MVC گفته ایم، یک درخواست با نشانی URL به سرور فرستاده می شود.