# آشنایی با OWIN و بررسی نقش آن در ASP.NET Core

در این مطلب می‌خواهیم نگاهی به قسمت‌های کلیدی OWIN و همچنین پروژه‌ی Katana بیندازیم و در نهایت نیز نقش OWIN را در ASP.NET Core بررسی خواهیم کرد. OWIN چیست؟ همانطور که می‌دانید OWIN یک specification اس

- Published: 2016-09-20
- Language: fa
- Tags: DNTips
- Canonical: https://sirwan.info/blog/fa/dntips-2514

---

> این نوشته نخستین بار در [دات‌نت تیپس](https://www.dntips.ir/post/2514) منتشر شده است.

<div class="postBody">در این مطلب می‌خواهیم نگاهی به قسمت‌های کلیدی OWIN و همچنین پروژه‌ی Katana بیندازیم و در نهایت نیز نقش OWIN را در ASP.NET Core بررسی خواهیم کرد.<div> <br/> <div> <br/> <div> <br/> <div> <b>OWIN چیست؟</b> </div> <div> <b> <br/> </b> </div> <div>همانطور که می‌دانید OWIN یک specification است که استانداری را بین وب‌سرور و وب‌اپلیکیشن‌ها تعریف کرده است. در واقع OWIN یکسری لایه‌ی انتزاعی را جهت ایجاد اپلیکیشن‌هایی که نحوه‌ی میزبانی آنها اهمیتی ندارد، تعریف خواهد کرد. به صورت خلاصه توسط این لایه‌ی انتزاعی می‌توانیم وابستگی بین وب‌سرور و وب‌اپلیکیشن را حذف کنیم. در این specification منظور از وب‌سرور یک delegate و همچنین یک دیکشنری است. در واقع هدف این است که وقتی درخواستی به این وب‌سرور ارسال شد، درخواست به قسمت‌های کوچکی تقسیم‌بندی شده و درون این دیکشنری قرار خواهند گرفت (این دیکشنری حاوی کلیدهای از پیش‌تعریف شده‌ای است که توسط OWIN تعریف شده‌اند). سپس این دیکشنری از طریق یک application function به درون pipeline ارسال خواهد شد و از یکسری <a href="https://www.dntips.ir/post/2443">middleware</a>  عبور خواهد کرد. در اینحالت می‌توانیم کنترلی را بر روی درخواست‌های وارده و صادره داشته باشیم. ایده‌ی middleware خیلی شبیه به HTTP moduleها در IIS است؛ اما تفاوت آن این است که middlewareها وابستگی‌ایی به IIS ندارند و همچنین مبتنی بر رویداد نیستند. هر middleware بعد از انجام تغییرات بر روی درخواست، تا زمان رسیدن دیکشنری به آخرین middleware، آن را به middleware بعدی ارسال خواهد کرد. در این حین می‌توانیم به response streams اطلاعاتی را append کنیم. وقتی دیکشنری از تمامی middlewareها عبور کرد، سرور مطلع خواهد شد و نتیجه را به کلاینت ارسال می‌کند. </div> <div> <hr/> <br/> </div> <div>استاندارد OWIN تعدادی کلید را درون یک دیکشنری تعریف کرده است که بعد از ورود به هر middleware مقداردهی خواهند شد. این کلیدها را می‌توانیم در دو دسته‌ی Request و Response بررسی کنیم.</div> <div> <b> <br/>
کلیدهای مربوط به Request</b> </div> <div> <div align="right"> <div align="right"> <table style="border: none;"> <tbody> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: white; background: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";
  color:white;'>ضروری؟ </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-top-color: white; border-bottom-color: white; border-left-color: white; border-right: none; background: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";
  color:white;'>نام کلید </span> </p> </td> <td style="width: 276.1pt; border-top-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-top-color: white; border-bottom-color: white; border-left-color: white; border-right: none; background: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";
  color:white;'>مقدار </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-right-color: rgb(112, 173, 71); border-bottom-color: rgb(112, 173, 71); border-left-color: rgb(112, 173, 71); border-top: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-top: none; border-right: none; border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestBody" </span> </b> </p> </td> <td style="width: 276.1pt; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-right-color: rgb(112, 173, 71); border-bottom-color: rgb(112, 173, 71); border-left-color: rgb(112, 173, 71); border-top: none; padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک </span> <span dir="LTR" style='Iranian Sans";'>Stream</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> همراه با  </span> <span dir="LTR" style='Iranian Sans";'>request body</span>.<span style='Iranian Sans";'> اگر </span> <span dir="LTR" style='Iranian Sans";'>body</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> برای </span> <span dir="LTR" style='Iranian Sans";'>request</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> وجود نداشته باشد، </span> <span dir="LTR" style='Iranian Sans";'>Stream.Null</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> به عنوان </span> <span dir="LTR" style='Iranian Sans";'>placeholder</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> قابل استفاده است.  </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-width: initial; border-style: none; border-color: initial; padding: 0cm 5.4pt;"> <p align="center" style='margin-bottom:
  .0001pt;text-align:center;Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestHeaders"  <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک دیکشنری به صورت </span> <b> <span dir="LTR" style='Iranian Sans";color:#7030A0;'>IDictionary&lt;string, string[]&gt;</span> </b> <span dir="RTL"> </span> <span dir="RTL"> </span> <b> <span style='Iranian Sans";color:#7030A0;'> <span dir="RTL"> </span> <span dir="RTL"> </span> </span> </b> <span style='Iranian Sans";'>از هدرهای درخواست. </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-top-color: rgb(112, 173, 71); border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); border-right: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestMethod"</span> </b> <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>رشته‌ایی حاوی نوع فعل متد </span> <span dir="LTR" style='Iranian Sans";'>HTTP</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> مربوط به درخواست (مانند </span> <span dir="LTR" style='Iranian Sans";'>GET and POST</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>) </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-width: initial; border-style: none; border-color: initial; padding: 0cm 5.4pt;"> <p align="center" style='margin-bottom:
  .0001pt;text-align:center;Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestPath"  <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span dir="LTR" style='Iranian Sans";'>path</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> درخواست شده
  به صورت </span> <span dir="LTR" style='Iranian Sans";'>string </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-top-color: rgb(112, 173, 71); border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); border-right: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestPathBase"</span> </b> <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>قسمتی از </span> <span dir="LTR" style='Iranian Sans";'>path</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> درخواست به صورت </span> <span dir="LTR" style='Iranian Sans";'>string </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-width: initial; border-style: none; border-color: initial; padding: 0cm 5.4pt;"> <p align="center" style='margin-bottom:
  .0001pt;text-align:center;Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestProtocol"  <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>نام و نسخه‌ی پروتکل (مانند </span> <span dir="LTR" style='Iranian Sans";'>HTTP/1.0 or HTTP/1.1</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>) </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-top-color: rgb(112, 173, 71); border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); border-right: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestQueryString"</span> </b> <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>رشته‌ای حاوی </span> <span dir="LTR" style='font-size:
  10.0pt;Iranian Sans";'>query string</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>؛ بدون علامت </span> <span dir="LTR"> </span> <span dir="LTR"> </span> <span dir="LTR" style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>?</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> (مانند </span> <b> <span dir="LTR" style='Iranian Sans";color:#7030A0;'>foo=bar&amp;baz=quux</span> </b> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>)  </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-right-color: rgb(112, 173, 71); border-bottom-color: rgb(112, 173, 71); border-left-color: rgb(112, 173, 71); border-top: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-top: none; border-right: none; border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style='margin-bottom:
  .0001pt;text-align:center;Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.RequestScheme"  <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-right-color: rgb(112, 173, 71); border-bottom-color: rgb(112, 173, 71); border-left-color: rgb(112, 173, 71); border-top: none; padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>رشته‌ایی حاوی </span> <span dir="LTR" style='font-size:
  10.0pt;Iranian Sans";'>URL scheme</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> استفاده شده در درخواست (مانند </span> <span dir="LTR" style='Iranian Sans";'>HTTP or HTTPS</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>) </span> </p> </td> </tr> </tbody> </table> <br/> </div> <div align="right"> <b> <br/> </b> </div> <div align="right"> <b>کلیدهای مربوط به Response</b> </div> <div align="right"> <div align="right"> <table style="border: none;"> <tbody> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: white; background: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";
  color:white;'>ضروری؟ </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-top-color: white; border-bottom-color: white; border-left-color: white; border-right: none; background: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";
  color:white;'>نام کلید </span> </p> </td> <td style="width: 276.1pt; border-top-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-top-color: white; border-bottom-color: white; border-left-color: white; border-right: none; background: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";
  color:white;'>مقدار </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-right-color: rgb(112, 173, 71); border-bottom-color: rgb(112, 173, 71); border-left-color: rgb(112, 173, 71); border-top: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-top: none; border-right: none; border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.ResponseBody" </span> </b> </p> </td> <td style="width: 276.1pt; border-right-width: 1pt; border-bottom-width: 1pt; border-left-width: 1pt; border-right-color: rgb(112, 173, 71); border-bottom-color: rgb(112, 173, 71); border-left-color: rgb(112, 173, 71); border-top: none; padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک </span> <span dir="LTR" style='Iranian Sans";'>Stream</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> جهت نوشتن  </span> <span dir="LTR" style='Iranian Sans";'>response body</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> در خروجی </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>بله </span> </p> </td> <td style="width: 148.8pt; border-width: initial; border-style: none; border-color: initial; padding: 0cm 5.4pt;"> <p align="center" style='margin-bottom:
  .0001pt;text-align:center;Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.ResponseHeaders"  <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک دیکشنری به صورت </span> <b> <span dir="LTR" style='Iranian Sans";color:#7030A0;'>IDictionary&lt;string, string[]&gt;</span> </b> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> از هدرهای  </span> <span dir="LTR" style='Iranian Sans";'>response</span> <span style='Iranian Sans";'> </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>خیر </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-top-color: rgb(112, 173, 71); border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); border-right: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.ResponseStatusCode"</span> </b> <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک عدد صحیح حاوی کد وضعیت </span> <span dir="LTR" style='Iranian Sans";'>HTTP response</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>؛ حالت پیش‌فرض 200 است. </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>خیر </span> </p> </td> <td style="width: 148.8pt; border-width: initial; border-style: none; border-color: initial; padding: 0cm 5.4pt;"> <p align="center" style='margin-bottom:
  .0001pt;text-align:center;Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.ResponseReasonPhrase"  <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-top: none; border-left-width: 1pt; border-left-color: rgb(112, 173, 71); border-bottom: none; border-right-width: 1pt; border-right-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک رشته حاوی </span> <span dir="LTR" style='font-size:
  10.0pt;Iranian Sans";'>reason
  phrase</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> مربوط به  </span> <span dir="LTR" style='Iranian Sans";'>status code</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>؛ اگر خالی باشد در نتیجه سرور
  بهتر است آن را مقداردهی کند. </span> </p> </td> </tr> <tr> <td style="width: 42.6pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>خیر </span> </p> </td> <td style="width: 148.8pt; border-top-width: 1pt; border-top-color: rgb(112, 173, 71); border-left: none; border-bottom-width: 1pt; border-bottom-color: rgb(112, 173, 71); border-right: none; padding: 0cm 5.4pt;"> <p align="center" style="margin-bottom:
  .0001pt;text-align:center;"> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span style='Iranian Sans";'> <span dir="LTR"> </span> <span dir="LTR"> </span>"owin.ResponseProtocol"</span> </b> <b> <span dir="RTL" style='Iranian Sans";'> </span> </b> </p> </td> <td style="width: 276.1pt; border-width: 1pt; border-color: rgb(112, 173, 71); padding: 0cm 5.4pt;"> <p style="
  text-align:right;direction:rtl;unicode-bidi:embed;"> <span style='Iranian Sans";'>یک رشته حاوی نام و نسخه‌ی پروتکل (مانند </span> <span dir="LTR" style='Iranian Sans";'>HTTP/1.0 or HTTP/1.1</span> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span>)؛ اگر خالی
  باشد؛ </span> <span dir="LTR"> </span> <span dir="LTR"> </span> <b> <span dir="LTR" style='Iranian Sans";color:#7030A0;'> <span dir="LTR"> </span> <span dir="LTR"> </span>“owin.RequestProtocol”</span> </b> <span dir="RTL"> </span> <span dir="RTL"> </span> <span style='Iranian Sans";'> <span dir="RTL"> </span> <span dir="RTL"> </span> به عنوان مقدار پیش‌فرض در نظر گرفته خواهد شد.</span> <span dir="LTR" style='Iranian Sans";'> </span> </p> </td> </tr> </tbody> </table> <br/> </div> <div align="right"> <b>Katana</b> </div> <div align="right">پروژه‌ی Katana یک پیاده‌سازی از استاندارد OWIN است که توسط مایکروسافت ایجاد شده است. مایکروسافت علاوه بر پیاده‌سازی OWIN، یکسری قابلیت دیگر را نیز به آن اضافه کرده است. برای شروع کار با Katana یک پروژه خالی از نوع ASP.NET Web Application را ایجاد کنید. در ادامه لازم است پکیج Microsoft.Owin.Host.SystemWeb را نیز نصب کنیم. همراه با نصب این پکیج، دو وابستگی دیگر نیز نصب خواهند شد؛ زیرا پیاده‌سازی OWIN درون پکیج Microsoft.Owin قرار دارد:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="XML" name="code">&lt;package id="Microsoft.Owin" version="3.0.1" targetFramework="net461" /&gt;&#10;&lt;package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net461" /&gt;&#10;&lt;package id="Owin" version="1.0" targetFramework="net461" /&gt;</pre>
 </div>
در ادامه نیاز به یک نقطه‌ی شروع برای اپلیکیشن‌مان داریم. طبق convention باید یک فایل را با نام Startup.cs با محتویات زیر ایجاد کنیم:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using Owin;&#10;namespace SimpleOwinWebApp&#10;{&#10;    public class Startup&#10;    {&#10;        public void Configuration(IAppBuilder app)&#10;        {&#10;&#10;        } &#10;    }&#10;}</pre>
 </div>
توسط IAppBuilder می‌توانیم middlewareها را به pipeline اضافه کنیم:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using Owin;&#10;namespace SimpleOwinWebApp&#10;{&#10;    public class Startup&#10;    {&#10;        public void Configuration(IAppBuilder app)&#10;        {&#10;            app.Use(async (ctx, next) =&gt;&#10;            {&#10;                await ctx.Response.WriteAsync("Hello");&#10;            });&#10;        } &#10;    }</pre>
 </div>
توسط متد Use، یک middleware را به صورت inline تعریف کرده‌ایم. متد Use یک delegate را از ورودی دریافت خواهد کرد و امضای آن به اینصورت است:
</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">Func&lt;IOwinContext, Func&lt;Task&gt;, Task&gt; handler</pre>
 </div> <br/> </div> </div>
 IOwinContext در واقع یک wrapper برای environment dictionaryایی است که در ابتدا به آن اشاره کردیم. در مثال قبل، از پراپرتی Response، جهت ارسال خروجی به کلاینت استفاده شده است. این پراپرتی در واقع معادل کلید owin.ResponseBody درون دیکشنری است. اما در اینجا به صورت strongly-typed و ساده به آن دسترسی داریم؛ هر چند که امکان کار با دیکشنری خام نیز وجود دارد. به عنوان مثال معادل مثال قبل بدون استفاده از پراپرتی Response، اینچنین خواهد بود:
 </div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">app.Use(async (ctx, next) =&gt;&#10;{&#10;   var response = ctx.Environment["owin.ResponseBody"] as Stream;&#10;   using (var writer = new StreamWriter(response))&#10;   {&#10;      await writer.WriteAsync("Hello");&#10;   }&#10;});</pre>
 </div> </div>
اکنون اگر پروژه را اجرا کنید، با وارد کردن هر آدرسی، پیام Hello درون مرورگر برایتان نمایش داده خواهد شد:</div> <div align="right"> <br/> </div> <div align="right"> <p style="margin-left: auto; margin-right: auto;"> <img src="/img/dntips/065e55f653c371c7d2fd.png" style="display: block; margin-left: auto; margin-right: auto; cursor: default;"/> </p> </div> <div align="right"> <br/> </div> <div align="right">به هر تعداد middleware که خواستید می‌توانید به pipeline اضافه کنید؛ اما باید دقت داشته باشید که ترتیب قرار دادن آنها اهمیت دارد.</div> <div align="right"> <b> <br/> </b> </div> <div align="right"> <b>Self-hosting OWIN</b> </div> <div align="right">در مثال قبلی، اپلیکیشن توسط IIS Express اجرا می‌شد. برای میزبانی درون یک کنسول اپلیکیشن، ابتدا یک پروژه‌ی Console Application را ایجاد کرده و پکیج Microsoft.Owin.SelfHost را نصب کنید. سپس کلاس Startup موردنظرتان را ایجاد کرده و در نهایت درون متد Main، کار راه‌اندازی سرور را انجام خواهیم داد: </div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using System;&#10;using Microsoft.Owin.Hosting;&#10;&#10;namespace SimpleOwinConsoleApp&#10;{&#10;    class Program&#10;    {&#10;        static void Main(string[] args)&#10;        {&#10;            using (WebApp.Start&lt;Startup&gt;("http://localhost:12345"))&#10;            {&#10;                Console.WriteLine("Listening to port 12345");&#10;                Console.WriteLine("Press Enter to end...");&#10;                Console.ReadLine();&#10;            }&#10;        }&#10;    }&#10;}</pre>
 </div> <br/> </div> <div align="right"> <b>OWIN در ASP.NET Core</b> </div> <div align="right">ASP.NET Core دارای مفهومی با عنوان pipeline است. این pipeline خیلی شبیه به OWIN است اما OWIN نیست؛ <a href="https://www.dntips.ir/post/2443">بلکه عملکرد آن شبیه به OWIN است</a>. به عنوان مثال اینبار به جای دیکشنری، شیء HttpContext را داریم. در ادامه یک پروژه‌ی ASP.NET Core Web Application از نوع Empty را شروع خواهیم کرد. اگر دقت کنید اینبار برای کلاس Startup باید دو متد را پیاده‌سازی کنیم:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using Microsoft.AspNetCore.Builder;&#10;using Microsoft.AspNetCore.Hosting;&#10;using Microsoft.AspNetCore.Http;&#10;using Microsoft.Extensions.DependencyInjection;&#10;using Microsoft.Extensions.Logging;&#10;&#10;namespace SimpleOwinCoreApp&#10;{&#10;    public class Startup&#10;    {&#10;        public void ConfigureServices(IServiceCollection services)&#10;        {&#10;        }&#10;&#10;        public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)&#10;        {&#10;            loggerFactory.AddConsole();&#10;&#10;            if (env.IsDevelopment())&#10;            {&#10;                app.UseDeveloperExceptionPage();&#10;            }&#10;&#10;            app.Run(async (context) =&gt;&#10;            {&#10;                await context.Response.WriteAsync("Hello World!");&#10;            });&#10;        }&#10;    }&#10;}</pre>
 </div> <br/> </div> <div align="right"> <b>متد Configure</b>: همانطور که در ابتدای مطلب مشاهده کردید این متد قبلاً در پروژه‌های مبتنی بر کاتانا Configuration نام داشت؛ همچنین به جای IAppBuilder اینبار IApplicationBuilder را داریم. مزیت ASP.NET Core این است که در هر جایی از اپلیکیشن می‌توانیم از سیستم DI توکار آن استفاده کنیم؛ در نتیجه علاوه بر IApplicationBuilder وابستگی‌های دیگری مانند IHostingEnvironment و ILoggerFactory را نیز می‌توانیم تزریق کنیم.</div> <div align="right"> <b>متد ConfigureServices</b>: در اینجا می‌توانیم سرویس‌های موردنیاز درون اپلیکیشن را برای IoC ریجستر کنیم.</div> <div align="right">در کد فوق استفاده از متد Use به معنای آخرین نقطه در pipeline است. یعنی جایی که response برگردانده خواهد شد و چیزی بعد از آن اجرا نخواهد شد؛ در واقع ارجاعی به middleware بعدی وجود ندارد.<br/> <br/> </div> <div align="right"> <b>ایجاد یک Middleware جدید</b> </div> <div align="right">تا اینجا تمامی کدها را به صورت inline نوشتیم. اما اگر بخواهیم middlewareمان قابلیت استفاده‌ی مجدد داشته باشد می‌توانیم تعاریف آن را به یک کلاس با ساختار زیر منتقل نمائیم:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;"> </div> </div> <div align="left" dir="ltr" style="direction: ltr;"> </div> <div align="left" dir="ltr" style="direction: ltr;">
<pre language="CSharp" name="code">using System.Threading.Tasks;&#10;using Microsoft.AspNetCore.Http;&#10;&#10;namespace SimpleOwinCoreApp.Middlewares&#10;{&#10;    public class SimpleMiddleware&#10;    {&#10;        private readonly RequestDelegate _next;&#10;&#10;        public SimpleMiddleware(RequestDelegate next)&#10;        {&#10;            _next = next;&#10;        }&#10;&#10;        public async Task Invoke(HttpContext ctx)&#10;        {&#10;            // قبل از فراخوانی میان‌افزار بعدی&#10;&#10;            await ctx.Response.WriteAsync("Hello DNT!");&#10;&#10;            await _next(ctx);&#10;&#10;            // بعد از فراخوانی میان‌افزار بعدی&#10;        }&#10;    }&#10;}</pre>
 </div> <br/> <div align="right">درون متد Invoke بعد از پردازش درخواست باید متد middleware بعدی را همراه با context جاری فراخوانی کنیم. در نتیجه قبل و بعد از فراخوانی middleware بعدی فرصت این را خواهیم داشت تا درخواست را پردازش کنیم. در نهایت برای استفاده از middleware فوق می‌توانیم از متد الحاقی UseMiddleware استفاده کنیم:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">app.UseMiddleware&lt;SimpleMiddleware&gt;();</pre>
 </div> <br/> </div> <div align="right"> <b>استفاده از middlewareهای مبتنی بر Katana در ASP.NET Core</b> </div> <div align="right">middlewareهایی را که برای Katana نوشته‌اید، درون یک اپلیکیشن ASP.NET Core نیز قابل استفاده هستند. برای اینکار با مراجعه به فایل project.json می‌توانید پکیج زیر را نصب کنید:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">"Microsoft.AspNetCore.Owin": "1.0.0"</pre>
 </div>
سپس درون متد Configure می‌توانید Owin را به pipeline اضافه کرده و middleware خود را ریجستر کنید:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">app.UseOwin(pipeline =&gt;&#10;{&#10;pipeline(next =&gt; new MyKatanaBasedMiddleware(next).Invoke)&#10;});</pre>
 </div> <br/> </div> <div align="right"> <b>مثال تکمیلی:</b> </div> <div align="right">در ادامه می‌خواهیم ماژول مطرح شده در <a href="https://www.dntips.ir/post/2347">این مطلب</a>  را به صورت یک middleware با قابلیت پذیرفتن تنظیمات، نوشته و سپس درون pipeline استفاده کنیم. برای شروع یک کلاس با نام IpBlockerMiddleware با محتویات زیر ایجاد خواهیم کرد: </div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using System.Linq;&#10;using System.Threading.Tasks;&#10;using Microsoft.AspNetCore.Http;&#10;&#10;namespace SimpleOwinAspNetCore.Middleware&#10;{&#10;    public class IpBlockerMiddleware&#10;    {&#10;        private readonly RequestDelegate _next;&#10;        private readonly IpBlockerOptions _options;&#10;&#10;        public IpBlockerMiddleware(RequestDelegate next, IpBlockerOptions options)&#10;        {&#10;            _next = next;&#10;            _options = options;&#10;        }&#10;&#10;        public async Task Invoke(HttpContext context)&#10;        {&#10;            var ipAddress = context.Request.Host.Host;&#10;            if (IsBlockedIpAddress(ipAddress))&#10;            {&#10;                context.Response.StatusCode = 403;&#10;                await context.Response.WriteAsync("Forbidden : The server understood the request, but It is refusing to fulfill it.");&#10;                return;&#10;            }&#10;            await _next.Invoke(context);&#10;        }&#10;&#10;        private bool IsBlockedIpAddress(string ipAddress)&#10;        {&#10;            return _options.Ips.Any(ip =&gt; ip == ipAddress);&#10;        }&#10;    }&#10;}</pre>
 </div>
در کدهای فوق لیست Ipها از پراپرتی Ips درون کلاس IpBlockerOptions دریافت خواهد شد:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using System.Collections.Generic;&#10;&#10;namespace SimpleOwinAspNetCore.Middleware&#10;{&#10;    public class IpBlockerOptions&#10;    {&#10;        public IpBlockerOptions()&#10;        {&#10;            Ips = new[] { "192.168.1.1" };&#10;        }&#10;        public IList&lt;string&gt; Ips { get; set; }&#10;    }&#10;}</pre>
 </div>
همچنین برای استفاده راحت‌تر از middleware، یک متد الحاقی را برای آن ایجاد کرده‌ایم و سپس پراپرتی Ips را توسط اینترفیس IConfigurationRoot دریافت کرده‌ایم:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">using System.Linq;&#10;using Microsoft.AspNetCore.Builder;&#10;using Microsoft.Extensions.Configuration;&#10;&#10;namespace SimpleOwinAspNetCore.Middleware&#10;{&#10;    public static class IpBlockerExtensions&#10;    {&#10;        public static IApplicationBuilder UseIpBlocker(this IApplicationBuilder builder, IConfigurationRoot configuration, IpBlockerOptions options = null)&#10;        {&#10;            return builder.UseMiddleware&lt;IpBlockerMiddleware&gt;(options ?? new IpBlockerOptions&#10;            {&#10;                Ips = configuration.GetSection("block_list").GetChildren().Select(p =&gt; p.Value).ToArray()&#10;            });&#10;        }&#10;    }&#10;}</pre>
 </div>
قبلاً در رابطه با <a href="https://www.dntips.ir/post/2451">فایل‌های کانفیگ</a> مطلبی را مطالعه کرده‌اید؛ در نتیجه نیازی به توضیح اضافه‌تری ندارد. تنها کاری که در اینجا انجام شده است، دریافت محتویات کلید block_list از فایل کانفیگ است. </div> <div align="right">محتویات فایل blockedIps.json:</div> <div align="left" dir="ltr" style="direction: ltr;">
<pre language="CSharp" name="code">{&#10;  "block_list": [&#10;    "192.168.1.1",&#10;    "localhost",&#10;    "127.0.0.1",&#10;    "172.16.132.151"&#10;  ]&#10;}</pre>
 </div> <br/> <div align="right">برای خواندن فایل فوق در برنامه نیز خواهیم داشت:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">public IConfigurationRoot Configuration { set; get; }&#10;&#10;public Startup(IHostingEnvironment env)&#10;{&#10;var builder = new ConfigurationBuilder()&#10;.SetBasePath(env.ContentRootPath)&#10;.AddJsonFile("blockedIps.json");&#10;Configuration = builder.Build();&#10;}</pre>
 </div>
در نهایت برای استفاده از middleware فوق خواهیم داشت:</div> <div align="right"> <div align="left" dir="ltr" style="direction:ltr;text-align:left;">
<pre language="CSharp" name="code">app.UseIpBlocker(Configuration);</pre>
 </div>
اکنون هر درخواستی که با آدرس‌های تعیین شده درون فایل blockedIps.json وارد pipeline شود، امکان استفاده‌ی از سایت را نخواهد داشت.</div> <div align="right"> <br/> </div> <div align="right">کدهای این مطلب را می‌توانید از <a href="https://github.com/SirwanAfifi/Owin_Samples">اینجا</a> دریافت کنید.</div> </div> </div> </div> </div></div>
