مطالب دوره‌ها
اصل معکوس سازی وابستگی‌ها
پیش از شروع این سری نیاز است با تعدادی از واژه‌های بکار رفته در آن به اختصار آشنا شویم؛ از این واژه‌ها به کرات استفاده شده و در طول دوره به بررسی جزئیات آن‌ها خواهیم پرداخت:

1) Dependency inversion principle یا DIP (اصل معکوس سازی وابستگی‌ها)
DIP یکی از اصول طراحی نرم افزار است و D آن همان D معروف SOLID است (اصول پذیرفته شده شیءگرایی).

2) Inversion of Control یا IOC (معکوس سازی کنترل)
الگویی است که نحوه پیاده سازی DIP را بیان می‌کند.

3) Dependency injection یا DI (تزریق وابستگی‌ها)
یکی از روش‌های پیاده سازی IOC است.

4) IOC container
به فریم ورک‌هایی که کار DI را انجام می‌دهند گفته می‌شود.


Dependency inversion principle چیست؟

اصل معکوس سازی وابستگی‌ها به این معنا است که بجای اینکه ماژول‌های سطح پایین سیستم، رابط‌های قابل استفاده‌ای از خود را در اختیار سطوح بالاتر سیستم قرار دهند، ماژول‌های قرار گرفته در سطوحی بالاتر، اینترفیس‌هایی را تعریف می‌کنند که توسط ماژول‌های سطح پایین پیاده سازی خواهند شد.
همانطور که ملاحظه می‌کنید به این ترتیب وابستگی‌های سیستم معکوس خواهند شد. نمونه‌ای از عدم استفاده از این طراحی را در دنیای واقعی به صورت رومزه با آن‌ها سر و کار داریم؛ مانند وسایل الکترونیکی قابل حملی که نیاز به شارژ مجدد دارند. برای مثال تلفن‌های همراه، دوربین‌های عکاسی دیجیتال و امثال آن.


هر کدام از این‌ها، رابط‌های اتصالی متفاوتی دارند. یکی USB2، یکی USB3 دیگری Mini USB و بعضی‌ها هم از پورت‌های دیگری استفاده می‌کنند. چون هر کدام از لایه‌های زیرین سیستم (در اینجا وسایل قابل شارژ) رابط‌های اتصالی مختلفی را ارائه داده‌اند، برای اتصال آن‌ها به منبع قدرت که در سطحی بالاتر قرار دارد، نیاز به تبدیلگرها و درگاه‌های مختلفی خواهد بود.
اگر در این نوع طراحی‌ها، اصل معکوس سازی وابستگی‌ها رعایت می‌شد، درگاه و رابط اتصال به منبع قدرت باید تعیین کننده نحوه طراحی اینترفیس‌های لایه‌های زیرین می‌بود تا با این آشفتگی نیاز به انواع و اقسام تبدیلگرها، روبرو نمی‌شدیم.


اگر وابستگی‌ها معکوس نشوند مطابق تصویر فوق، کلاس سطح بالایی را خواهیم داشت که به اینترفیس کلاس‌های سطح پایین وابسته است. البته در اینجا اینترفیس یک کلمه عمومی است و بیشتر نحوه در معرض دید و استفاده قرار دادن اعضای یک کلاس مد نظر بوده است تا اینکه مثلا الزاما اینترفیس‌های زبان خاصی مدنظر باشند.
مشکلی که در این حالت به زودی بروز خواهد کرد، افزایش کلاس‌های سطح پایین و بیشتر شدن وابستگی کلاس‌های سطح بالا به آن‌ها است. به این ترتیب قابلیت استفاده مجدد خود را از دست خواهند داد.


در تصویر فوق حالتی را مشاهده می‌کنید که وابستگی‌ها معکوس شده‌اند. تغییر مهمی که در اینجا نسبت به حالت قبل رخ داده است، بالا بردن اینترفیس، به بالای خط میانی است که در تصویر مشخص گردیده است. این خط، معرف تعریف لایه‌های مختلف سیستم است. به عبارتی کلاس‌های سطح بالا در لایه دیگری نسبت به کلاس‌های سطح پایین قرار دارند. در اینجا اجازه داده‌ایم تا کلاس لایه بالایی اینترفیس مورد نیاز خود را تعریف کند. این نوع اینترفیس‌ها در زبان سی شارپ می‌توانند یک کلاس Abstract و یا حتی یک Interface متداول باشند.
با معکوس شدن وابستگی‌ها، لایه سطح بالا است که به لایه زیرین عنوان می‌کند: تو باید این امکانات را در اختیار من قرار دهی تا بتوانم کارم را انجام دهم.


اکنون اگر در یک سیستم واقعی تعداد کلاس‌های سطح پایین افزایش پیدا کنند، نیازی نیست تا کلاس سطح بالا تغییری کند. کلاس‌های سطح پایین تنها باید عملکردهای تعیین شده در اینترفیس را پیاده سازی کنند. و این برخلاف حالتی است که وابستگی‌ها معکوس نشده‌اند:



تاریخچه اصل معکوس سازی وابستگی‌ها

اصل معکوس سازی وابستگی‌ها در نشریه C++ Report سال 1996 توسط شخصی به نام Bob Martin (معروف به Uncle Bob!) برای اولین بار مطرح گردید. ایشان همچنین یکی از آغاز کنندگان گروهی بود که مباحث Agile را ارائه کردند. به علاوه ایشان برای اولین بار مباحث SOLID را در دنیای شیءگرایی معرفی کردند (همان مباحث معروف هر کلاس باید تک مسئولیتی باشد، باز باشد برای توسعه، بسته برای تغییر و امثال آن که ما در این سری مباحث قسمت D آن‌را در حالت بررسی هستیم).

مطابق تعاریف Uncle Bob:
الف) ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند. هر دوی این‌ها باید به Abstraction وابسته باشند.
ب) Abstraction نباید وابسته به جزئیات باشد. جزئیات (پیاده سازی‌ها) باید وابسته به Abstraction باشند.


مثال برنامه کپی

اگر به مقاله Uncle Bob مراجعه کنید، یکی از مواردی را که عنوان کرده‌اند، یک برنامه کپی است که می‌تواند اطلاعات را از صفحه کلید دریافت و در یک چاپگر، چاپ کند.


حال اگر به این مجموعه، ذخیره سازی اطلاعات بر روی دیسک سخت را اضافه کنیم چطور؟ به این ترتیب سیستم با افزایش وابستگی‌ها، پیچیدگی و if و elseهای بیشتری را خواهد یافت؛ از این جهت که سطح بالایی سیستم به صورت مستقیم وابسته خواهد بود به ماژول‌های سطح پایین آن.
روشی را که ایشان برای حل این مشکل ارائه داده‌اند، معکوس کردن وابستگی‌ها است:


در اینجا سطح بالایی سیستم وابسته است به یک سری تعاریف Abstract خواندن و یا نوشتن؛ بجای وابستگی مستقیم به پیاده سازی‌های سطح پایین آن‌ها.
در این حالت اگر تعداد Readers و یا Writers افزایش یابند، باز هم سطح بالایی سیستم نیازی نیست تغییر کند زیرا وابسته است به یک اینترفیس و نه پیاده سازی آن که محول شده است به لایه‌های زیرین سیستم.
این مساله بر روی لایه بندی سیستم نیز تاثیرگذار است. در روش متداول برنامه نویسی، لایه بالایی به صورت مستقیم متدهای لایه‌های زیرین را صدا زده و مورد استفاده قرار می‌دهد. به این ترتیب هر تغییری در لایه‌های مختلف، بر روی سایر لایه‌ها به شدت تاثیرگذار خواهد بود. اما در حالت معکوس سازی وابستگی‌ها، هر کدام از لایه‌های بالاتر، از طریق اینترفیس از لایه زیرین خود استفاده خواهد کرد. در این حالت هرگونه تغییری در لایه‌های زیرین برنامه تا زمانیکه اینترفیس تعریف شده را پیاده سازی کنند، اهمیتی نخواهد داشت.


مثال برنامه دکمه و لامپ

مثال دیگری که در مقاله Uncle Bob ارائه شده، مثال برنامه دکمه و لامپ است. در حالت متداول، یک دکمه داریم که وابسته است به لامپ. برای مثال وهله‌ای از لامپ به دکمه ارسال شده و سپس دکمه آن‌را کنترل خواهد کرد (خاموش یا روشن). مشکلی که در اینجا وجود دارد وابستگی دکمه به نوعی خاص از لامپ است و تعویض یا استفاده مجدد از آن به سادگی میسر نیست.
راه حلی که برای این مساله ارائه شده، ارائه یک اینترفیس بین دکمه و لامپ است که خاموش و روشن کردن در آن تعریف شده‌اند. اکنون هر لامپی (یا هر وسیله الکتریکی دیگری) که بتواند این متدها را ارائه دهد، در سیستم قابل استفاده خواهد بود.

مطالب
معرفی سرویس‌های ارائه شده توسط شرکت‌های گوگل، آمازون و مایکروسافت در قالب رایانش ابری - قسمت دوم
همانطور که که در قسمت اول اشاره گردید، شرکت گوگل به ارائه سرویس‌های متنوعی بر اساس فناوری رایانش ابری پرداخته است. در این بخش به معرفی سرویس‌های ابری ارائه شده توسط شرکت آمازون پرداخته می‌شود. 
وب سایت این شرکت برای پوشش ترافیک در تمام طول سال به میزان بالایی زیرساخت نرم افزاری و سخت افزاری خود را گسترش داده است. بر همین اساس، این شرکت به منظور جلوگیری از اتلاف منابع ایجاد شده و کسب منافع مالی قابل توجه، به مرور امکان استفاده از منابع شبکه­‌اش را برای کاربران مهیا ساخته است. آمازون در سال 2006 سکوی وب سرویس خود را به عنوان مدل مصرفی در دسترس توسعه دهندگان قرار داد. این شرکت از طریق مجازی سازی سخت افزار بر روی Xen Hypervisor می­تواند سرورهای مجازی ایجاد کند. وب سرویس­های آمازون (Amazon Web Services -AWS) چیزی که اصولاً ظرفیت استفاده نشده زیر ساخت شبکه آمازون است را می­گیرد و آن را به تجارتی سودمند تبدیل می­کند.
سرویس‌های آمازون بی تردید نمایانگر بزرگترین IaaS محض در دنیای امروز هستند. ابر محاسباتی توسعه پذیر آمازون(Amazon Elastic Compute Cloud - EC2) که بزرگترین مولفه محصولات آمازون است در سال 2009 بالغ بر 220 میلیون دلار درآمد داشته است و تخمین زده می‌شود که EC2 بر روی بیش از چهل هزار سرور جهانی که در شش نقطه جهان تقسیم شده اند، اجرا می‌گردد.

صفحه اصلی وب سرویس‌های آمازون

سرویس‌ها و اجزای وب سرویس آمازون:

وب سرویس­های آمازون دارای اجزای زیادی می­باشند. تعدادی از این سرویس­ها برای ارائه خدمات پردازشی و تعداد دیگری برای ارائه فضای ذخیره­سازی، عرضه شده‌­اند. در ادامه گروهی از این سرویس­ها معرفی می­گردد: 

  1. ابر محاسباتی توسعه پذیر آمازون (EC2)
این سرویس، استفاده و مدیریت سرورهای اختصاصی مجازی که سیستم عامل­های لینوکس یا ویندوز را بر روی Xen Hypervisor  اجرا می­کنند، میسر کرده است. نمونه­‌های ماشین با توان­های پردازشی مختلف موجود می­باشد و بر اساس محاسبات/ساعت اجاره می­شوند. برنامه­‌های مستقر بر روی این ماشین­ها بسیار توسعه پذیر و با تحمل پذیری بالای خطا می­باشند. ذکر تفاوت میان یک نمونه ماشین و یک تصویر ماشین می­تواند به درک مفاهیم موجود در سرویس آمازون کمک کند. به طور کلی نمونه ماشین در واقع تقلید یا همسان­سازی(Emulation) سکوی سخت­افزاری مانند x86 و غیره بر روی لایه نرم­افزار مجازی Xen می­باشد. در حالی که تصویر ماشین، نرم افزار و سیستم عاملی است که در سطح یک نمونه ماشین اجرا می­شود و می­توان به محتویات یک درایو راه‌­انداز تشبیه نمود. تعدادی از ابزارهایی که برای پشتیبانی سرویس­های EC2 استفاده می­شوند به شرح زیر است:

  • سرویس صف ساده آمازون(Simple Queue Service):  یک صف پیام یا سیستم تراکنش برای برنامه­‌های مبتنی بر اینترنت توزیع شده می­باشد. این سرویس تضمین می­کند که پیام­ها حتی در زمانی که مؤلفه‌ای موجود نیست، گم نشود و برای انتقال پیام میان مؤلفه‌های مختلف که هرکدام کار جداگانه‌­ای را انجام می­دهند، بسیار مناسب است.
  • سرویس آگاه سازی ساده آمازون(Simple Notification Service):  ): وب سرویسی است که می­تواند پیام یک برنامه را منتشر کند و آن­ها را به برنامه­‌ها یا مشترکین دیگر منتقل کند. SNS  متدی را برای راه­‌اندازی فعالیت­ها ارائه می­نماید که برنامه­‌ها را قادر می­سازد تا در مورد اطلاعات جدید یا تغییر یافته از آن‌ها نظرسنجی شود یا به روز رسانی­‌ها را انجام دهند.
  • سرویس نظارت ابر آمازون(Amazon Cloud Watch):  کنسولی را فراهم می­کند که در آن مصرف منابع، شاخص­‌های کلیدی عملکرد سایت و نشانگرهای عملیاتی برای عواملی همچون تقاضای پردازشگر، مصرف دیسک و ورودی و خروجی شبکه را ارائه می­دهد.  نتایج معیارهایی که توسط آن کسب ­می­شود برای فعال‌سازی قابلیتی به نام Auto Scaling  مورد استفاده قرار می­گیرد که به صورت خودکار می­تواند یک سایت EC2 را بر مبنای مجموعه‌­ای از قوانین که توسعه دهنده ایجاد می­کند، توسعه دهد.
  •   توازن بار منعطف(Elastic Load Balancing): نمونه­‌های ماشین آمازون(Amazon Machine Image) با استفاده از این قابلیت، دارای امکان توازن بار ترافیکی می­شوند. این قابلیت هنگامی که نمونه‌­ای دچار شکست می­شود آن را کشف کرده و ترافیک را به یک نمونه سالم حتی نمونه‌­ای در محیط­‌های دیگر AWS  مسیریابی مجدد می­کند.
    2.  سیستم ذخیره سازی ساده آمازون (Amazon Simple Storage Service - S3)
یک سیستم ذخیره­سازی و پشتیبان گیری آنلاین است و دارای قابلیت انتقال سریع داده به نام  AWS Import/Export  می­باشد و داده را با استفاده از شبکه داخلی آمازون از AWS به دستگاه­‌های ذخیره­‌سازی قابل حمل منتقل می­نماید. این سیستم دسترسی به واحدهای اطلاعاتی را از طریق API وب S3 به کمک استانداردهای SOAP یا REST فراهم می‌کند. از آنجایی که دسترسی به داده با پهنای باند پایین میسر است، از این نوع حافظه بیشتر برای کارهای غیر عملیاتی مانند آرشیو و بازیابی یا پشتیبان گیری از دیسک استفاده می­شود.
    3.  انبار بلوک بسط پذیر آمازون (Amazon Elastic Block Store - EBS)
سیستمی است برای ساخت دیسک‌­های مجازی یا دستگاه­‌های ذخیره­سازی بلوکی که برای نمونه­‌های ماشین آمازون در EC2  مورد استفاده قرار می­گیرند. مزیت این سیستم این است دارای عملکرد بالاتر و قابل اعتماد‌تر از آمازون S3 است به همین دلیل یک واسط ذخیره سازی داده عملیاتی بسیار ارزشمند برای AWS  است. همچنین هزینه ایجاد EBS  مناسب‌تر از مشابه S3 می‌باشد. هر EBS پس از ایجاد بر روی یک نمونه مشخص سوار یا نصب می­شود و تنها برای آن نمونه قابل دسترسی خواهد بود. از این‌رو اشتراک آن­ها بین نمونه­‌ها امکان پذیر نمی­باشد. این سرویس بر اساس فضای ذخیره سازی مصرفی، مدت زمان استفاده و تعداد تقاضاهای ورودی/خروجی قیمت گزاری می­شود.
    4.  پایگاه داده ساده آمازون (Amazon Relational Database Service - RDS) 
این سرویس نمونه­‌های پایگاه داده MySQL را برای پشتیبانی از وب سایت و سایر برنامه‌­هایی که متکی بر سرویس‌­های داده محور(Data Driven) می­باشند، ایجاد می­کند. این سرویس برنامه­‌های پایگاه داده­‌ای که قبلاً در محیط دیگری ساخته شده­‌ا‌ند را پشتیبانی می­نماید و هر برنامه­‌ای که با پایگاه داده MySQL کار می‌کند با RDS نیز کار خواهد کرد. یکی از ویژگی­‌های مهم RDS سیستم پشتیبان گیری خودکار برای داده‌­های درون پایگاه و گزارشات تراکنش MySQL می­باشد. فایل­های پشتیبان به مدت 8 روز ذخیره می­شوند و علاوه بر آن امکان تصویر برداری از پایگاه داده نیز وجود دارد.

مدل قیمت گذاری:

قیمت گذاری انواع مختلف نمونه­ ماشین آمازون به سه پارامتر وابسته است. اولین مورد سیستم عامل مورد استفاده است. دومین عامل مرکز داده­‌ای است که در آن قرار گرفته و سومین عامل مدت زمانی است که اجرا می­شود. نرخ‌­ها بر مبنای ساعت محاسبه می­شوند. علاوه بر آن مبالغ اضافی نیز بابت موارد زیر اخذ می­شود: 

  • میزان داده منتقل شده 
  • آدرس‌های IP اختصاصی
  • استفاده سرور اختصاصی مجازی از فضای ذخیره­سازی بلوکی توسعه پذیر آمازون
  • استفاده از  توازن بار توسعه پذیر برای دو یا چند سرور 
  • سایر ویژگی­های مورد نیاز 
به طور کلی نمونه­ ماشین‌­های آمازون که ذخیره شده‌­اند و خاموش هستند، هزینه کلی نگهداری کمتری دارند و مبلغ اضافه به ازای هر ساعت محاسبه نمی­شود و فقط هزینه حافظه مورد استفاده پرداخت می­گردد. به طور کلی پرداخت هزینه به منظور استفاده از نمونه­ ماشین آمازون در سه مدل مقدور است: 
  • نمونه مبتنی بر تقاضا: نرخ ساعتی بدون التزام طولانی مدت
  • نمونه رزرو شده: خرید قراردادی هر نمونه با هزینه به مراتب پایین‌تر به ازای هر ساعت بعد از رزرو اولیه

  • نمونه نقطه­‌ای: این متد برای قیمت گذاری بر روی ظرفیت استفاده نشده EC2 بر مبنای قیمت نقطه فعلی است. این قابلیت، قیمت­‌های بسیار پایین را به همراه خواهد داشت اما در زمان­‌های مختلف فرق می­کند یا در زمانی که ظرفیت مازادی نباشد، در دسترس نخواهد بود. 

در جدول زیر  مشخصات سخت افزاری انواع نمونه ماشین­‌های آمازون ذکر شده‌­اند و با توجه به قیمت گذاری نمونه‌ها بر اساس موقعیت جغرافیایی که در آن قرار گرفته‌­اند، بسیار متنوع است، از ذکر این موارد اجتناب نموده و علاقه‌مندان به کسب اطلاعات بیشتر به وب سایت شرکت آمازون ارجاع داده می­شوند. همچنین ذکر این نکته ضروری است که شرکت آمازون به منظور تست و توسعه سرویس‌های ارائه شده، اکانت یکساله رایگان با امکان استفاده از سرویس‌ها به صورت محدود، ارائه می‌نماید.
نوع 
موتور محاسبه    حافظه اصلی(GB)    ذخیره سازی(GB) سکو   
 ریز نمونه   تا دو واحد محاسباتی در انفجار بار    0.613   EBS    32 یا 64 بیتی 
 نمونه کوچک   یک واحد محاسباتی    1.7    160   32 بیتی   
 نمونه بزرگ   چهار واحد محاسباتی    7.5    850    64 بیتی 
 نمونه بسیار بزرگ   هشت واحد محاسباتی    15    1690    64 بیتی 
   
   
مطالب
آشنایی با Feature Toggle - بخش اول
فرض کنید میخواهید برای بخش‌هایی از نرم افزاری که طراحی کرده‌اید ، امکانی را در نظر بگیرید که بتوانید زمانیکه نرم افزار در حال استفاده‌است، قابلیت‌هایی از آن‌را فعال یا غیرفعال نمایید؛ بدون اینکه نرم افزار از دسترس خارج شود. Feature Toggle که تحت عنوان Feature Flag هم شناخته می‌شود همین امکان را برای ما به ارمغان می‌آورد و ما را قادر می‌سازد تا قابلیت‌هایی را از نرم افزار، فعال یا غیرفعال کنیم، بدون اینکه نیاز باشد نرم افزار از دسترس مشتریان خارج شود و یا نیاز باشد نسخه‌ی جدیدی از نرم افزار  منتشر شود. برای مثال قابلیت ثبت نام کاربران را در بازه‌های خاصی غیرفعال کنیم و یا فرض کنید قابلیت جدیدی به نرم افزار اضافه کرده‌اید و میخواهید بعد از پابلیش، در یک بازه زمانی که نرم افزار شما بازدید کننده‌های کمتری دارد، آن‌را موقتا فعال کنید، نتیجه خروجی را ببینید و سپس آن را غیر فعال نمایید. در ادامه این مقاله سعی خواهیم کرد ابتدا با یک مثال ساده با این قابلیت آشنا شویم و سپس به معرفی یکی از کتابخانه‌های محبوب در این زمینه بپردازیم.
Feature Toggle چیزی بیشتر از یک دستور IF نیست، اگر شرط مورد نظر برقرار بود، کد را اجرا میکند، در غیر اینصورت از اجرای آن بخش صرف نظر میکند.
IF (currentYear<2023){
alert('Wear a mask!');
}
در قطعه کد فوق، سال جاری را چک کرده‌ایم و گفته‌ایم اگر سال جاری کمتر از سال 2023 بود، به بازدید کننده یک پیغام را نمایش دهیم. حال فرض کنید بیماری کرونا، پیش از سال 2023 از بین برود، ولی طبق این شرط همچنان پیغام به کاربران نمایش داده میشود. میتوانیم فعال و غیر فعال بودن نمایش این پیغام را یا از دیتابیس و یا از فایل appsetting.json  بخوانیم که در این حالت  به صورت زیر می‌باشد :
var showCoronaAlert=_cofiguration.GetValue<bool>("Features:showCoronaAlert"); // or read this from Database
If(showCoronaAlert){
alert(Wear a amask!);
}
در این روش بجای اینکه تاریخ را چک کنیم و بر اساس آن تصمیم بگیریم که آیا پیغامی نمایش داده شود یا نه، وضعیت نمایش آن را از فایل تنظیمات و یا دیتابیس خوانده‌ایم. در این حالت دیگر نیازی به تغییر و انتشار نسخه‌ی جدیدی از نرم افزار نیست و فقط کافی‌است مقدار مربوط به نمایش پیغام را در دیتابیس و یا فایل تنظیمات، به روزسانی نماییم.

 کتابخانه  Microsoft.FeatureManagement
کتابخانه  Microsoft.FeatureManagement  توسط تیم اژور پیاده سازی و نوشته شده‌است و برای خواندن اطلاعات، از همان IConfiguration استفاده میکند که ما را قادر می‌سازد تنظیمات را از منابع مختلفی بخوانیم  و همچنین  قابلیت‌های آن فراتر از تنظیم یک مقدار با true/false می‌باشد که در ادامه با بعضی از آنها آشنا خواهیم شد.
ابتدا نیاز هست این کتابخانه را به صورت زیر نصب نماییم :
Install-Package Microsoft.FeatureManagement

سپس نیاز هست در متد ConfigureService، سرویس مربوطه را اضافه نماییم :
using Microsoft.FeatureManagement;
public void ConfigureServices(IServiceCollection services)
{
    services.AddFeatureManagement();
}

این کتابخانه به صورت پیش فرض، اطلاعات feature‌ها را از بخشی (section) تحت عنوان FeatureManagement  از فایل appsetting.json می‌خواند. پس نیاز داریم این بخش را در appsetting.json تعریف نماییم  ( لیست تمامی قابلیت‌هایی را که قصد داریم به صورت داینامیک فعال/غیرفعال کنیم، در این بخش اضافه خواهیم کرد):
"FeatureManagement": {
   
}
اگر تمایل داشتید از اسم دیگری برای بخش تنظیمات، در فایل appsetting. json  استفاده نمایید، می‌توانید به صورت زیر این کار را انجام دهید :
public void ConfigureServices(IServiceCollection services)
{
 services.AddFeatureManagement(Configuration.GetSection("MyFeatureManagement"))
}
در این مقاله از همان اسم پیش فرض استفاده شده است.
افزودن یک قابلیت جدید
"FeatureManagement": {
   "MaskAlert":true
}

همان مثال بالا را  در بخش FeatureManagement  اضافه کرده‌ایم  و مقدار true را به معنی فعال بودن، برای آن در نظر گرفته‌ایم. این حالت، ساده‌ترین روش ثبت یک قابلیت با استفاده از این کتابخانه می‌باشد. برای بررسی وضعیت هر کدام از قابلیت‌ها باید اینترفیس  IFeatureManager   را به کلاس مربوطه تزریق نماییم و سپس بر اساس نام قابلیت، وضعیت آن را بررسی نماییم:
 public class HomeController : Controller
    {
        private readonly IFeatureManager _featureManager;

        public HomeController(IFeatureManager featureManager)
        {
            _featureManager = featureManager;
        }
        public async Task<IActionResult> Index()
        {
            if(await _featureManager.IsEnabledAsync("MaskAlert"))
            {
                // show messeage
            }

            return View();
        }
    }
اگر نیاز هست از اسم دیگری برای بخش (section)

فعال سازی بر اساس تاریخ (TimeWindowsFilter)
یکی از قابلیت‌های این کتابخانه، فعال سازی بر اساس بازه زمانی هست. اگر نیاز دارید یک قابلیت در یک بازه‌ی خاص فعال شود، میتوانید از این قابلیت استفاده کنید. برای فعال سازی این امکان، باید فیلتر TimeWindowFilter را که به صورت توکار به همراه کتابخانه وجود دارد، به صورت زیر در متد configureServices ثبت نماییم:
public void ConfigureServices(IServiceCollection services)
{ 
    services.AddFeatureManagement().AddFeatureFilter<TimeWindowFilter>();
}

و سپس یک Feature را در بخش FeatureManagement همانند زیر تعریف میکنیم که توسط آن مشخص کرده‌ایم این قابلیت در بازه‌ی زمانی بین دو تاریخ تعریف شده، فعال باشد :
 "FeatureManagement": {
    "EmergencyBanner": {
      "EnabledFor": [
        {
          "Name": "Microsoft.TimeWindow",
          "Parameters": {
            "Start": "01 Mar 2021 12:00:00 +00:00",
            "End": "01 Apr 2021 12:00:00 +00:00"
          }
        }
      ]
    }
  }
و نحوه‌ی بررسی فعال بودن آن، همانند روش قبل می‌باشد و فقط کافیست اسم Feature را به متد IsEnabledAsync بدهیم:
if(await _featureManager.IsEnabledAsync("EmergencyBanner")){
// show Emergency banner 
}

 پارامتر‌های Start و End میتوانند به صورت تکی هم استفاده شوند؛ به این معنا که میتوانید فقط پارامتر start را مقدار دهی کنید و در این حالت از تاریخ مورد نظر به بعد، Feature مورد نظر فعال می‌باشد و یا اگر فقط پارامتر End مقدار دهی شود، Feature مورد نظر فقط تا تاریخ تعیین شده فعال هست و بعد از آن برای همیشه غیرفعال می‌شود.
در زیر، نمونه‌ای از این حالت تنظیم شده‌است :
"FeatureManagement": {
    "EmergencyBanner": {
      "EnabledFor": [
        {
          "Name": "Microsoft.TimeWindow",
          "Parameters": {
            "End": "01 Apr 2021 12:00:00 +00:00"
          }
        }
      ]
    }
  }

فیلتر‌های سفارشی
از دیگر مزایای این کتابخانه این هست که محدود به فیلترهای توکار خود آن نیستیم و امکان توسعه و نوشتن فیلتر‌های سفارشی را به ما میدهد. برای مثال اگر یک قابلیت را در نرم افزار پیاده سازی کرده‌ایم که میخواهیم فقط بر روی مرورگر‌های خاصی در دسترس باشد، میتوانیم به صورت زیر این کار را انجام دهیم:
ابتدا در appsetting.json قابلیت (Feature) مورد نظر را به صورت زیر تعریف می‌کنیم :
"FeatureManagement": {
    "ChatV2": {
      "EnabledFor": [
        {
          "Name": "BrowserFilter",
          "Parameters": {
            "AllowedBrowsers": [ "Chrome" ]
          }
        }
      ]
    }
  }
سپس فیلتر سفارشی را به صورت زیر پیاده سازی میکنیم :
[FilterAlias("BrowserFilter")]
public class BrowserFilter:IFeatureFilter
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public BrowserFilter(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        }

        public Task<bool> EvaluateAsync(FeatureFilterEvaluationContext context)
        {
            var userAgent = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"].ToString();
            var settings = context.Parameters.Get<BrowserFilterSettings>();
            return Task.FromResult(settings.AllowedBrowsers.Any(userAgent.Contains));
        }
    }

کلاس BrowserFilter :
  public class BrowserFilterSettings
    {
        public string[] AllowedBrowsers { get; set; }
    }
بعد از پیاده سازی فیلتر فوق نیاز هست فیلتر سفارشی را که در بالا نوشتیم، در متد ConfigureServices ثبت نماییم. با توجه به اینکه برای تشخیص نوع مروگر کاربر نیاز هست  هدر درخواست را بررسی کنیم، پس نیاز هست IHttpContextAccessor را هم ثبت نماییم:
public void ConfigureServices(IServiceCollection services)
        {
            services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.AddFeatureManagement()
                .AddFeatureFilter<BrowserFilter>();
        }
و برای بررسی فعال بودن قابلیت مورد نظر فقط کافیست مانند قبل، اسم قابلیت مورد نظر را به صورت زیر بررسی کنیم :
if(await _featureManager.IsEnabledAsync("ChatV2")){
// do something 
}

* از دیگر قابلیت‌های این کتابخانه، فعال و غیر فعال کردن کنترلر و اکشن متدها بر اساس وضعیت Feature‌ها می‌باشد که در بخش دوم این مقاله به توضیح این موارد خواهیم پرداخت.
نظرات مطالب
اجرای وظایف زمان بندی شده با Quartz.NET - قسمت اول
سلام برادر.
Quartz.NET رو دست کم نگیرید. بسیار بسیار قدرتمنده. این کتابخانه برای ردیابی وظایف از مفهومی با عنوان JobStore استفاده می‌کنه. به طور پیش فرض داده‌های مربوط به ردیابی وضعیت اجرای وظیفه‌ها در حافظه‌ی RAM قرار می‌گیرند که Quartz.NET اون رو به عنوان RAMJobStore میشناسه. اما برای سناریوهایی همانند آنچه که شما گفتید، پشتیبانی از پیش تعبیه شده برای ذخیره‌ی داده‌های ردیابی رو در پایگاه داده هم فراهم می‌کنه و این قابلیت رو با عنوان AdoJobStore میشناسه.
این کتابخانه در حال حاضر از پایگاه‌های داده‌ی SqlServer، Oracle، MySql، SQLite و Firebird پشتیبانی می‌کنه . فایل اسکریپت برای تولید جداول مورد نیاز در بسته‌ی دانلودی اون هست.
در ضمن، Quartz.NET با خودش سرویسی به همراه داره که میتونه به عنوان سرویس‌های سیستم عامل معرفی بشه تا هرگاه سیستم بالا اومد، اون سرویس به طور خودکار وظیفه‌ها رو از یک فایل با فرمت XML میخونه و اجرا می‌کنه.

در مورد 4 سال پیش که فرمودید، بله بنده هم پیاده سازی‌های مختلفی دیدم. حتی یکی از هموطنان، با استفاده از Cache، برای برای برنامه‌های ASP.NET، قابلیت زمانبندی (هر چند بسیار محدود) ارائه داده بود. استفاده از Timer هم روتین‌ترین چیزی هست که به ذهن همه میرسه اما در قسمت پرسش و پاسخ سایت Quartz.NET، دلایل مطلوب نبودن استفاده‌ی صِرف از Timer در قسمت "?Why not just use System.Timers.Timer" گفته شده. 
مطالب
استفاده از افزونه‌های Owin مخصوص سایر نگارش‌های ASP.NET در ASP.NET Core
همانطور که اطلاع دارید یکسری از کتابخانه‌های کمکی و ثالث ASP.NET Core همچون OData و SignalR ، Thinktecture IdentityServer هنوز در حال تکمیل هستند و از آنجایی که هر روزه محبوبیت ASP.NET Core در بین برنامه نویسان در حال افزایش است و خیلی از پروژه‌های نرم افزاری که امروزه start میخورند، از این فریم ورک جدید استفاده میکنند، پس خیلی به اهمیت این مقوله افزوده میشود که بتوان از تکنولوژی‌های فوق در پروژه‌های جدید نیز استفاده کرد و یکی از معقول‌ترین راه‌های ممکن آن، پیاده سازی Owin  در کنار ASP.NET Core Pipeline میباشد. بدین معنا که ما قصد نداریم owin pipeline را جایگزین آن نماییم؛ همانطور که در ادامه‌ی این مقاله گفته خواهد شد، از هر دو معماری (افزونه‌های Owin مخصوص نگارش کامل دات نت و همچنین خود ASP.NET Core) در کنار هم استفاده خواهیم کرد.
پیشنیاز این مقاله آشنایی با ASP.NET Core و MiddleWare و همچنین آشنایی با Owin میباشد. همانطور که عرض کردم اگر مقاله‌ی پیاده سازی OData را مطالعه کرد‌ه‌اید و هم اکنون قصد و یا علاقه‌ی به استفاده‌ی از آن را در پروژه‌ی ASP.NET Core خود دارید، میتوانید این مقاله را دنبال نمایید.
پس تا کنون متوجه شدیم که هدف از این کار، توانایی استفاده از ابزارهایی است که با Owin سازگاری کامل را دارند و همچنین به نسخه‌ی پایدار خود رسیده‌اند. بطور مثال IdentityServer 4 در حال تهیه است که با ASP.NET Core سازگار است. اما هنوز چند نسخه‌ی beta از آن بیرون آمده و به پایداری کامل نرسیده است. همچنین زمان توزیع نهایی آن نیز دقیقا مشخص نیست.
شما برای استفاده از ASP.NET Core RTM 1.0 احتیاج به Visual studio 2015 update 3 دارید. ابتدا یک پروژه‌ی #C از نوع Asp.Net Core Web Application  را «به همراه full .Net Framework» به نام OwinCore میسازیم.
در حال حاضر بدلیل اینکه پکیج‌هایی مانند OData, SignalR هنوز به نسخه‌ی Net Coreی خود آماده نشده‌اند (در حال پیاده سازی هستند)، پس مجبور به استفاده از full .Net framework هستیم و خوب مسلما برنامه در این حالت چند سکویی نخواهد بود. اما به محض اینکه آن‌ها آماده شدند، میتوان full .Net را کنار گذاشته و از NET Core. استفاده نمود و از آنجایی که Owin فقط یک استاندارد هست، هیچ مشکلی با NET Core. نداشته و برنامه را میتوان بدان منتقل کرد و از مزایای چند سکویی بودن آن نیز بهره برد. پس مشکل در حال حاضر Owin نبوده و مجبور به منتظر بودن برای آماده شدن این پکیج‌ها خواهیم بود. مثال عملی این قضیه نیز Nancy است که نسخه‌ی NET Core.ی آن با استفاده از Owin در ASP.NET Core پیاده سازی شده است. در اینجا مثال عملی آن را میتوانید پیدا کنید.


در قسمت بعد، قالب را هم از نوع empty انتخاب مینماییم.


در ادامه فایل project.json را باز کرده و در قسمت dependencies، تغییرات زیر را اعمال نمایید.

قبل از اینکه شما را از این همه وابستگی نگران کنم، باید عرض کنم فقط Microsoft.Owin , Microsoft.AspNetCore.Owin، پکیج‌های اجباری هستند؛ باقی آن‌ها برای نشان دادن انعطاف پذیری بالای این روش میباشند:

"dependencies": {
    "Microsoft.AspNet.OData": "5.9.1",
    "Microsoft.AspNet.SignalR": "2.2.1",
    "Microsoft.AspNet.WebApi.Client": "5.2.3",
    "Microsoft.AspNet.WebApi.Core": "5.2.3",
    "Microsoft.AspNet.WebApi.Owin": "5.2.3",
    "Microsoft.AspNetCore.Diagnostics": "1.0.0",
    "Microsoft.AspNetCore.Hosting": "1.0.0",
    "Microsoft.AspNetCore.Mvc": "1.0.0",
    "Microsoft.AspNetCore.Owin": "1.0.0",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
    "Microsoft.Extensions.Logging.Console": "1.0.0",
    "Microsoft.Net.Http": "2.2.29",
    "Microsoft.Owin": "3.0.1",
    "Microsoft.Owin.Diagnostics": "3.0.1",
    "Microsoft.Owin.FileSystems": "3.0.1",
    "Microsoft.Owin.StaticFiles": "3.0.1",
    "Newtonsoft.Json": "9.0.1"
  },
//etc...

بعد از ذخیره کردن این فایل، در پنجره‌ی Output خود شاهد دانلود شدن این پکیج‌ها خواهید بود. در اینجا پکیج‌های مربوط به Owin, Odata, SignalR را مشاهد می‌کنید. ضمن اینکه در کنار آن، AspNetCore.Mvc را نیز مشاهده میفرمایید. دلیل این کار این است که این دو نوع متفاوت قرار است در کنار هم کار کنند و هیچ مشکلی با دیگری ندارند.

در مسیر اصلی پروژه‌ی خود کلاسی به نام OwinExtensions را با محتوای زیر بسازید:

namespace OwinCore
{
    public static class OwinExtensions
    {
        public static IApplicationBuilder UseOwinApp(
            this IApplicationBuilder aspNetCoreApp,
            Action<IAppBuilder> configuration)
        {
            return aspNetCoreApp.UseOwin(setup => setup(next =>
            {
                AppBuilder owinAppBuilder = new AppBuilder();

                IApplicationLifetime aspNetCoreLifetime = (IApplicationLifetime)aspNetCoreApp.ApplicationServices.GetService(typeof(IApplicationLifetime));

                AppProperties owinAppProperties = new AppProperties(owinAppBuilder.Properties);

                owinAppProperties.OnAppDisposing = aspNetCoreLifetime?.ApplicationStopping ?? CancellationToken.None;

                owinAppProperties.DefaultApp = next;

                configuration(owinAppBuilder);

                return owinAppBuilder.Build<Func<IDictionary<string, object>, Task>>();
            }));
        }
    }
}

یک Extension Method به نام UseOwinApp اضافه شده به IApplicationBuilder که مربوط به ASP.NET Core میباشد و درون آن نیز AppBuilder را که مربوط به Owin pipeline میباشد، نمونه سازی کرده‌ایم که باعث میشود Owin pipeline بر روی ASP.NET Core pipeline سوار شود.

حال میخواهیم یک Middleware سفارشی را با استفاده از Owin نوشته و در Startup پروژه، آن را فراخوانی نماییم. کلاسی به نام AddSampleHeaderToResponseHeadersOwinMiddleware را با محتوای زیر تولید مینماییم:

namespace OwinCore
{
    public class AddSampleHeaderToResponseHeadersOwinMiddleware : OwinMiddleware
    {
        public AddSampleHeaderToResponseHeadersOwinMiddleware(OwinMiddleware next)
            : base(next)
        {
        }
        public async override Task Invoke(IOwinContext context)
        {
            //throw new InvalidOperationException("ErrorTest");

            context.Response.Headers.Add("Test", new[] { context.Request.Uri.ToString() });

            await Next.Invoke(context);
        }
    }
}

کلاسی است که از owinMiddleware ارث بری کرده و در متد override شده‌ی Invoke نیز با استفاده از IOwinContext، به پیاده سازی Middleware خود میپردازیم. Exception مربوطه را comment کرده (بعدا در مرحله‌ی تست از آن نیز استفاده مینماییم) و در خط بعدی در هدر response هر request، یک شیء را به نام Test و با مقدار Uri آن request، میسازیم.

خط بعدی هم اعلام میدارد که به Middleware بعدی برود.

در ادامه فایل Startup.cs را باز کرده و اینگونه متد Configure را تغییر دهید:

public void Configure(IApplicationBuilder aspNetCoreApp, IHostingEnvironment env)
        {
            aspNetCoreApp.UseOwinApp(owinApp =>
            {
                if (env.IsDevelopment())
                {
                    owinApp.UseErrorPage(new ErrorPageOptions()
                    {
                        ShowCookies = true,
                        ShowEnvironment = true,
                        ShowExceptionDetails = true,
                        ShowHeaders = true,
                        ShowQuery = true,
                        ShowSourceCode = true
                    });
                }

                owinApp.Use<AddSampleHeaderToResponseHeadersOwinMiddleware>();
            });
        }

مشاهده میفرمایید با استفاده از UserOwinApp میتوانیم Middleware‌های Owinی خود را register نماییم و نکته‌ی قابل توجه این است که در کنار آن نیز می‌توانیم از IHostingEnviroment مربوط به ASP.NET core استفاده نماییم. owinApp.UseErrorPage از Microsoft.Owin.Diagnostics گرفته شده است و در خط بعدی نیز Middleware شخصی خود را register کرده‌ایم. پروژه را run کرده و در response این را مشاهد مینمایید.

اکنون اگر در Middleware سفارشی خود، آن Exception را از حالت comment در بیاوریم، در صورتیکه در حالت development باشیم، با این صفحه مواجه خواهیم شد:

Exception مربوطه را به حالت comment گذاشته و ادامه میدهیم.

برای اینکه نشان دهیم Owin و ASP.NET Core pipeline در کنار هم میتوانند کار کنند، یک Middleware را از نوع ASP.NET Core نوشته و آن را register مینماییم. کلاسی جدیدی را به نام AddSampleHeaderToResponseHeadersAspNetCoreMiddlware با محتوای زیر میسازیم:

namespace OwinCore
{
    public class AddSampleHeaderToResponseHeadersAspNetCoreMiddlware
    {
        private readonly RequestDelegate Next;

        public AddSampleHeaderToResponseHeadersAspNetCoreMiddlware(RequestDelegate next)
        {
            Next = next;
        }

        public async Task Invoke(HttpContext context)
        {
            //throw new InvalidOperationException("ErrorTest");

            context.Response.Headers.Add("Test2", new[] { "some text" });

            await Next.Invoke(context);
        }
    }
}

متد Configure در Startup.cs را نیز اینگونه تغییر میدهیم

public void Configure(IApplicationBuilder aspNetCoreApp, IHostingEnvironment env)
        {
            aspNetCoreApp.UseOwinApp(owinApp =>
            {
                if (env.IsDevelopment())
                {
                    owinApp.UseErrorPage(new ErrorPageOptions()
                    {
                        ShowCookies = true,
                        ShowEnvironment = true,
                        ShowExceptionDetails = true,
                        ShowHeaders = true,
                        ShowQuery = true,
                        ShowSourceCode = true
                    });
                }

                owinApp.Use<AddSampleHeaderToResponseHeadersOwinMiddleware>();
            });

            aspNetCoreApp.UseMiddleware<AddSampleHeaderToResponseHeadersAspNetCoreMiddlware>();
        }

اکنون AddSampleHeaderToResponseHeadersAspNetCoreMiddlware رجیستر شده است و بعد از run کردن پروژه و بررسی header response باید این را ببینیم

میبینید که به ترتیب اجرای Middleware‌ها، ابتدا Test مربوط به Owin و بعد آن Test2 مربوط به ASP.NET Core تولید شده است.

حال اجازه دهید Odata را با استفاده از Owin پیاده سازی نماییم. ابتدا کلاسی را به نام Product با محتوای زیر تولید نمایید:

namespace OwinCore
{
    public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Price { get; set; }
    }
}

حال کلاسی را به نام ProductsController با محتوای زیر میسازیم:

namespace OwinCore
{
    public class ProductsController : ODataController
    {
        [EnableQuery]
        public IQueryable<Product> Get()
        {
            return new List<Product>
            {
                 new Product { Id = 1, Name = "Test" , Price = 10 }
            }
            .AsQueryable();
        }
    }
}

اگر مقاله‌ی پیاده سازی Crud با استفاده از OData را مطالعه کرده باشید، قاعدتا با این کد‌ها آشنا خواهید بود. ضمن اینکه پرواضح است که OData هیچ وابستگی به entity framework ندارد.

برای config آن نیز در Startup.cs پروژه و متد Configure، تغییرات زیر را اعمال مینماییم.

public void Configure(IApplicationBuilder aspNetCoreApp, IHostingEnvironment env)
        {
            //aspNetCoreApp.UseMvc();

            aspNetCoreApp.UseOwinApp(owinApp =>
            {
                if (env.IsDevelopment())
                {
                    owinApp.UseErrorPage(new ErrorPageOptions()
                    {
                        ShowCookies = true,
                        ShowEnvironment = true,
                        ShowExceptionDetails = true,
                        ShowHeaders = true,
                        ShowQuery = true,
                        ShowSourceCode = true
                    });
                }
                // owinApp.UseFileServer(); as like as asp.net core static files middleware
                // owinApp.UseStaticFiles(); as like as asp.net core static files middleware
                // owinApp.UseWebApi(); asp.net web api / odata / web hooks

                HttpConfiguration webApiConfig = new HttpConfiguration();
                ODataModelBuilder odataMetadataBuilder = new ODataConventionModelBuilder();
                odataMetadataBuilder.EntitySet<Product>("Products");
                webApiConfig.MapODataServiceRoute(
                    routeName: "ODataRoute",
                    routePrefix: "odata",
                    model: odataMetadataBuilder.GetEdmModel());
                owinApp.UseWebApi(webApiConfig);

                owinApp.MapSignalR();

                //owinApp.Use<AddSampleHeaderToResponseHeadersOwinMiddleware>();
            });

            //aspNetCoreApp.UseMiddleware<AddSampleHeaderToResponseHeadersAspNetCoreMiddlware>();
        }

برای config مخصوص Odata، به HttpConfiguration نیاز داریم. بنابراین instanceی از آن گرفته و برای مسیریابی Odata از آن استفاده مینماییم.

با استفاده از پیاده سازی که از استاندارد Owin انجام دادیم، مشاهده کردید که Odata را همانند یک پروژه‌ی معمولی asp.netی، config نمودیم. در خط بعدی هم SignalR را مشاهده مینمایید.

اکنون اگر آدرس زیر را در مرورگر خود وارد نمایید، پاسخ زیر را از Odata دریافت خواهید کرد:

http://localhost:YourPort/odata/Products

بعد از فرستادن request فوق، باید response زیر را دریافت نمایید:

{ 
 "@odata.context":"http://localhost:4675/odata/$metadata#Products","value":[
    {
      "Id":1,"Name":"Test","Price":10
    }
  ]
}

تعداد زیادی Owin Middleware موجود همانند Thinktecture IdentityServer, NWebSec, Nancy, Facebook OAuth , ... هم با همان آموزش راه اندازی بر روی Owin که دارند میتوانند در ASP.NET Core نیز استفاده شوند و زمانی که نسخه‌ی ASP.NET Core اینها به آمادگی کامل رسید، با کمترین تغییری میتوان از آنها استفاده نمود.
اگر در پیاده سازی مقاله‌ی فوق با مشکل رو به رو شدید (اگر مراحل به ترتیب اجرا شوند، مشکلی نخواهید داشت) میتوانید از Github ، کل این پروژه را clone کرده و همچنین طبق commit‌های منظم از طریق history آن، مراحل جلو رفتن پروژه را دنبال نمایید.
نظرات مطالب
امکان ساخت برنامه‌های دسکتاپ چندسکویی Blazor در دات نت 6
این مورد AuthenticationStateProvider یکی از سرویس‌های توکار بلیزور میباشد که  AddServerSideBlazor موجب افزوده شدن آن به سیستم میشود. در این حالت هم اگر بخواهیم حتی این متد را هم صدا بزنیم باز موجب خطاهای دیگری هم میشود.
بعضی از سرویس‌ها هم مثل اتصال به دیتابیس به عنوان مثال از رشته اتصال موجود در فایل‌های appSettings خوانده میشوند که نیاز به کلاس Configuration هم دارند.
مطالب
مروری بر کتابخانه ReactJS - قسمت دوم - نصب و پیکربندی React‌JS برای Visual Studio Code

برای شروع به نصب و پیکربندی، باید بدانیم به چه چیزهایی احتیاج داریم. قطعا به کتابخانه React نیاز داریم. اما بسته به نوع کدنویسی که میخواهیم در پیش بگیریم، احتمالا به کتابخانه‌های دیگری هم احتیاج پیدا خواهیم کرد. در قسمت قبل نحوه‌ی ساخت یک تگ HTML، با React آورده شد. دوباره به آن نگاهی بیاندازیم:

var ClickableImage = function (props) {
    return (
        <a href={props.href}>
            <img src={props.src} />
        </a>
    )
};
میان یک فایل جاوااسکریپت، از تگ‌های HTML استفاده شده‌است. چرا و چطور؟! 

React از دو روش برای ساخت تگ‌ها استفاده میکند. روش ساده‌تر همین مثالی است که در بالا آمده؛ یعنی از تگ‌های HTML را به صورت مستقیم استفاده می‌کند. روش دیگر، استفاده از زبان جاوااسکریپت به تنهایی است. مثلا تگ‌های <a> و <img>  بالا به صورت زیر نوشته میشوند:

var ClickableImage = function(props) {
    React.createElement(
        "a", 
        {href: props.href}, 
        React.createElement(
            "img",
            {src: props.src}
        )
    )
};

وقتی تصور کنیم که قرار است یک جدول یا یک فرم را ایجاد کنیم، ارزش روش ساده‌تر، مشخص میشود. در واقع تگ‌هایی که استفاده شده، واقعا تگ‌های HTML نیستند؛ چیزی هستند به نام JSX.  


JSX

JSX زبان یا روشی است که اجازه میدهد از تگ‌های مشابه با HTML در جاوااسکریپت استفاده کنیم. به دلیل تفاوت‌های مختصری که دارند، گفته شد که این تگ‌ها دقیقا HTML نیستند. برای مثال در تگ‌های HTML خاصیت‌های class و for را داریم؛ اما در تگ‌های JSX باید به ترتیب از className و htmlFor استفاده کنیم. مسئله بعدی این است که اساسا JSX همراه با React ارائه نشده و برای اینکه بتوانیم از JSX استفاده کنیم، نیاز به ابزاری اضافه داریم تا JSX را برای JavaScript و مرورگر ترجمه کند که فیسبوک، Babel را پیشنهاد میدهد. اگر از JSX بدون ابزار مترجم استفاده کنیم با پیام خطای زیر مواجه می‌شویم. 

  > Uncaught SyntaxError: Unexpected token

یعنی کاراکتر شروع (>) تگ‌ها را تشخیص نمیدهد.


نصب کتابخانه‌ها

این کتابخانه‌ها را می‌شود به مدل‌های مختلفی دریافت و پیکربندی کرد. بسته به نوع پروژه و محیط توسعه و پیکربندی‌های خاص هر پروژه، روش کار میتواند متفاوت باشد. هدف اصلی، مروری بر امکانات React است. پس ساده‌ترین روش نصب را برای ادامه کار انتخاب میکنیم. مانند هر کتابخانه‌ی دیگری میشود بطور یکجا React و Babel را از سایت‌های اصلی یا Github دانلود و به پروژه اضافه و استفاده کرد؛ مثل jQuery و Bootstrap. اما راه استاندارد و پیشنهاد شده، استفاده از ابزارهای مدیریت بسته‌ها مثل npm است. در قدم اول با فرض بر اینکه VSCode و npm بر روی سیستم نصب هستند، اول یک پوشه خالی را در VSCode به عنوان پروژه باز میکنیم و از منوی View -> Integrated Terminal  را انتخاب میکنیم. در ترمینال باز شده دستور نصب زیر را وارد میکنیم.

npm install react react-dom
با این کار پوشه node_modules به ریشه پروژه اضافه میشود که حاوی کتابخانه React است. پوشه node_modules مختص به React نیست. هر کتابخانه‌ای را که به این صورت نصب کنیم، به این پوشه اضافه میشود. مرحله بعد، نصب کتابخانه Babel جهت استفاده‌ی از JSX است. کتابخانه Babel یک مترجم بزرگ است که اجزای مختلفی دارد. ما به حداقل‌هایی از آن برای ترجمه تگ‌های JSX  احتیاج داریم. برای این کار همانند قبل، ترمینال را انتخاب میکنیم و دستور نصب زیر را اجرا میکنیم. با این دستور نصب، کتابخانه مختصر babel-standalone به پوشه node_modules اضافه میشود.
npm install babel-standalone

نحوه استفاده

فایل index.html را به ریشه پروژه اضافه کنید و کدهای زیر را درون تگ Body قرار دهید: 

<div id="reactTestContainer"></div>

<script src="node_modules/react/dist/react.min.js"></script>
<script src="node_modules/react-dom/dist/react-dom.min.js"></script>
<script src="node_modules/babel-standalone/babel.min.js"></script>
<script src="react-test.js" type="text/babel"></script>

برای کار با کتابخانه React به دو فایل react.js و react-dom.js نیاز داریم. اولی بخش اصلی کتابخانه و دومی برای ساخت تگ‌ها و تبادل با بخش HTML DOM استفاده میشود؛ مثلا اضافه کردن تگ‌های ساخته شده به HTML. ذکر ویژگی "type="text/babel برای فایل‌هایی که در آنها از تگ‌های JSX استفاده شده ضروری است؛ در غیر اینصورت Babel  تشخیص نمیدهد که کار ترجمه را برای چه فایلهایی باید انجام دهد. در نهایت قطعه کد زیر را در فایل react-test.js وارد کنید. 

var ClickableImage = function (props) {
    return (
        <a href={props.href}>
            <img src={props.src} />
        </a>
    )
};

ReactDOM.render(
    <ClickableImage href="http://google.com" src="google.jpg"/>, 
    document.getElementById("reactTestContainer")
)

با اجرا کردن پروژه، تصویری قابل کلیک به مقصد گوگل، در تگ <div>، با ویژگی "id=”reactTestContainer ایجاد خواهد شد.

تا به این قسمت متوجه شدیم که کتابخانه React چیست و چطور میشود از آن استفاده کرد. در قسمت بعد نگاهی دقیق‌تر به کامپوننت‌های React خواهیم داشت.

مطالب
OutputCache در ASP.NET MVC
مقدمه

OutputCaching باعث می‌شود خروجیِ یک اکشن متد در حافظه نگهداری شود. با اعمال این نوع کشینگ، ASP.NET در خواست‌های بعدی به این اکشن را تنها با بازگرداندن همان مقدار قبلی ِ نگهداری شده در کش، پاسخ می‌دهد. در حقیقت با OutputCaching از تکرار چند باره کد درون یک اکشن در فراخوانی‌های مختلف جلوگیری کرده‌ایم. کش کردن باعث می‌شود که کارایی و سرعت سایت افزایش یابد؛ اما باید دقت کنیم که چه موقع و چرا از کَش کردن استفاده میکنیم و چه موقع باید از این کار امتناع کرد. 


فواید کَش کردن

- انجام عملیات هزینه دار فقط یکبار صورت میگیرد. (هزینه از لحاظ فشار روی حافظه سرور و کاهش سرعت بالا آمدن سایت)

- بار روی سرور در زمان‌های پیک کاهش می‌یابد.

- سرعت بالا آمدن سایت بیشتر میشود. 


چه زمانی باید کَش کرد؟ 

- وقتی محتوای نمایشی برای همه کاربران یکسان است.

- وقتی محتوای نمایشی برای نمایش داده شدن، فشار زیادی روی سرور تحمیل میکند.

- وقتی محتوای نمایشی به شکل مکرر در طول روز باید نمایش داده شود.

- وقتی محتوای نمایشی به طور مکرر آپدیت نمی‌شود. (در مورد تعریف کیفیت "مکرر"، برنامه نویس بهترین تصمیم گیرنده است) 


طرح مساله 

فرض کنید صفحه اول سایت شما دارای بخش‌های زیر است :

خلاصه اخبار بخش علمی، خلاصه اخبار بخش فرهنگی ، ده کامنت آخر، لیستی از کتگوری‌های موجود در سایت.

روش‌های مختلفی برای کوئری گرفتن وجود دارد، به عنوان مثال ما به کمک یک یا چند کوئری و توسط یک ViewModel جامع، میخواهیم اطلاعات را به سمت ویو ارسال کنیم. پس در اکشن متد Index ، حجم تقریبا کمی از اطلاعات را باید به کمک کوئری(کوئری های) تقریبا پیچیده ای دریافت کنیم و اینکار به ازای هر ریکوئست هزینه دارد و فشار به سرور وارد خواهد شد. از طرفی میدانیم صفحه اول ممکن است در طول یک یا چند روز تغییر نکند و همچنین شاید در طول یکساعت چند بار تغییر کند! به هر حال در جایی از سایت قرار داریم که کوئری (کوئری های) مورد نظر زیاد صدا زده میشوند ، در حقیقت صفحه اول احتمالا بیشترین فشار ترافیکی را در بین صفحات ما دارد، البته این فقط یک احتمال است و ما دقیقا از این موضوع اطلاع نداریم.

یکی از راه‌های انجام یک کش موفق و دانستن لزوم کش کردن، این است که دقیقا بدانیم ترافیک سایت روی چه صفحه ای بیشتر است. در واقع باید بدانیم در کدام صفحه "هزینه‌ی اجرای عملیات موجود در کد" بیشترین است.

فشار ترافیکی(ریکوئست‌های زیاد) و آپدیت‌های روزانه‌ی دیتابیس را، در دو کفه ترازو قرار دهید؛ چه کار باید کرد؟ این تصمیمی است که شما باید بگیرید. نگرانی خود را در زمینه آپدیت‌های روزانه و ساعتی کمتر کنید؛ در ادامه راهی را معرفی میکنیم که آپدیت‌های هر از گاهِ شما، در پاسخِ ریکوئست‌ها دیده شوند. کمی کفه‌ی کش کردن را سنگین کنید.

به هر حال، فعال کردن قابلیت کش کردن برای یک اکشن، بسیار ساده است، کافیست ویژگی ( attribute ) آن را بالای اکشن بنویسید :

[OutputCache(Duration = "60", Location = OutputCacheLocation.Server)]
        public ActionResult Index()
        {
            //کوئری یا کوئری‌های لازم برای استفاده در صفحه اصلی و تبدیل آن به یک ویو مدل جامع
        }
[OutputCache(CacheProfile = "FirstPageIndex",Location=OutputCacheLocation.Server)]
        public ActionResult Index()
        {
            //کوئری یا کوئری‌های لازم برای استفاده در صفحه اصلی و تبدیل آن به یک ویو مدل جامع
        }

دو روش فوق برای کش کردن خروجی Index  از لحاظ عملکرد یکسان است، به شرطی که در حالت دوم در وب کانفیگ و در بخش system.web آن ، یک پروفایل ایجاد کنیم کنیم :

    <caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="FirstPageIndex" duration="60"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>

در حالت دوم ما یک پروفایل برای کشینگ ساخته ایم و در ویژگی بالای اکشن متد، آن پروفایل را صدا زده ایم. از لحاظ منطقی در حالت دوم، چون امکان استفاده مکرر از یک پروفایل در جاهای مختلف فراهم شده، روش بهتری است. محل ذخیره کش نیز در هر دو حالت سرور تعریف شده است.

برای تست عملیات کشینگ، کافیست یک BreakPoint  درون Index قرار دهید و برنامه را اجرا کنید. پس از اجرا، برنامه روی Break Point می‌ایستد و اگر F5 را بزنیم، سایت بالا می‌آید. بار دیگر صفحه را رفرش کنیم، اگر این "بار دیگر" در کمتر از 60 ثانیه پس از رفرش قبلی اتفاق افتاده باشد برنامه روی Break Point متوقف نخواهد شد، چون خروجی اکشن، در کش بر روی سرور ذخیره شده است و این یعنی ما فشار کمتری به سرور تحمیل کرده ایم، صفحه با سرعت بالاتری در دسترس خواهد بود.

ما از تکرار اجرای کد جلوگیری کرده ایم و عدم اجرای کد بهترین نوع بهینه سازی برای یک سایت است. [اسکات الن، پلورال سایت]


چطور زمان مناسب برای کش کردن یک اکشن را انتخاب کنیم؟

- کشینگ با زمان کوتاه؛ فرض کنید زمان کش را روی 1 ثانیه تنظیم کرده اید. این یعنی اگر ریکوئست هایی به یک اکشن ارسال شود و همه در طول یک ثانیه اتفاق بیفتد، آن اکشن فقط برای بار اول اجرا میشود، و در بارهای بعد(در طول یک ثانیه) فقط محتوای ذخیره شده در آن یک اجرا، بدون اجرای جدید، نمایش داده میشود. پس سرور شما فقط به یک ریکوئست در ثانیه در طول روز جواب خواهد داد و ریکوئست‌های تقریبا همزمان دیگر، در طول همان ثانیه، از نتایج آن ریکوئست (اگر موجود باشد) استفاده خواهند کرد

- کشینگ با زمان طولانی؛ ما در حقیقت با اینکار منابع سرور را حفاظت میکنیم، چون عملیاتِ هزینه دار(مثل کوئری‌های حجیم) تنها یکبار در طول زمان کشینگ اجرا خواهند شد. مثلا اگر تنظیم زمان روی عدد 86400 تنظیم شود(یک روز کامل)، پس از اولین ریکوئست به اکشن مورد نظر، تا 24 ساعت بعد، این اکشن اجرا نخواهد شد و فقط خروجی آن نمایش داده خواهد شد. آیا دلیلی دارد که یک کوئری هزینه دار را که قرار نیست خروجی اش در طول روز تغییر کند به ازای هر ریکوئست یک بار اجرا کنیم؟   

اگر اطلاعات موجود در دیتابیس را تغییر دهیم چه کار کنیم که کشینگ رفرش شود؟ 

فرض کنید در همان مثال ابتدای این مقاله، شما یک پست به دیتابیس اضافه کرده اید، اما چون مثلا duration مربوط به کشینگ را روی 86400 تعریف کرده اید تا 24 ساعت از زمان ریکوئست اولیه نگذرد، سایت آپدیت نخواهد شد و محتوا همان چیزهای قبلی باقی خواهند ماند. اما چاره چیست؟

کافیست در بخش ادمین، وقتی که یک پست ایجاد میکنید یا پستی را ویرایش میکند در اکشن‌های مرتبط با Create یا Edit یا Delete چنین کدی را پس از فرمان ذخیره تغییرات در دیتابیس، بنویسید: 

Response.RemoveOutputCacheItem(Url.Action("index", "home"));

واضح است که ما داریم کشینگ مرتبط با یک اکشن متد مشخص را پاک میکنیم. با اینکار در اولین ریکوئست پس از تغییرات اعمال شده در دیتابیس، ASP.NET MVC چون میبیند کَشی برای این اکشن وجود ندارد، متد را اجرا میکند و کوئری‌های درونش را خواهد دید و اولین ریکوئست پیش از کَش شدن را انجام خواهد داد. با اینکار کشینگ ریست شده است و پس از این ریکوئست و استخراج اطلاعات جدید، زمان کشینگ صفر شده و آغاز میشود.

میتوانید یک دکمه در بخش ادمین سایت طراحی کنید که هر موقع دلتان خواست کلیه کش‌ها را به روش فوق پاک کنید! تا اپلیکیشن منتظر ریکوئست‌های جدید بماند و کش‌ها دوباره ایجاد شوند. 


جمع بندی

ویژگی OutputCatch دارای پارامترهای زیادیست و در این مقاله فقط به توضیح عملکرد این اتریبیوت اکتفا شده است. بطور کلی این مبحث ظاهر ساده ای دارد، ولی نحوه استفاده از کشینگ کاملا وابسته به هوش برنامه نویس است و پیچیدگی‌های مرتبط با خود را دارد. در واقع خیلی مشکل است که بتوانید یک زمان مناسب برای کش کردن تعیین کنید. باید برنامه خود را در یک محیط شبیه سازی تحت بار قرار دهید و به کمک اندازه گیری و محاسبه به یک قضاوت درست از میزان زمان کش دست پیدا کنید. گاهی متوجه خواهید شد، از مقدار زیادی از حافظه سیستم برای کش کردن استفاده کرده اید و در حقیقت آنقدر ریکوئست ندارید که احتیاج به این هزینه کردن باشد.

یکی از روش‌های موثر برای دستیابی به زمان بهینه برای کش کردن استفاده از CacheProfile درون وب کانفیگ است. وقتی از کشینگ استفاده میکنید، در همان ابتدا مقدار زمانی مشخص برای آن در نظر نگرفته اید(در حقیقت مقدار زمان مشخصی نمیدانید) پس مجبور به آزمون و خطا و تست و اندازه گیری هستید تا بدانید چه مقدار زمانی را برای چه پروفایلی قرار دهید. مثلا پروفایل هایی به شکل زیر تعریف کرده اید و نام آنها را به اکشن‌های مختلف نسبت داده اید. به راحتی میتوانید از طریق دستکاری وب کانفیگ مقادیر آن را تغییر دهید تا به حالت بهینه برسید، بدون آنکه کد خود را دستکاری کنید. 

<caching>
      <outputCacheSettings>
        <outputCacheProfiles>
          <add name="Long" duration="86400"/>
          <add name="Average" duration="43600"/>
          <add name="Short" duration="600"/>
        </outputCacheProfiles>
      </outputCacheSettings>
    </caching>

برای مطالعه جزئیات بیشتر در مورد OutputCaching مقالات زیر منابع مناسبی هستند.

[اینجا ] و [اینجا ]

مطالب
بررسی امکانات Bootstrap 4
دنیای وب کلاینت، در اواخر سال میلادی جاری دستخوش تغییرات بسیاری خواهد شد. از جهتی JavaScript با بروز رسانی موتور خود با نام و نسخه‌ی javascript ecmascript 6 ظاهرا قصد دارد تا تغییرات شگرفی را در دنیای اسکریپتی آشفته‌ی کلاینت بدهد. به همین علت فریم ورک‌های SPA یا single page app همانند AngularJs نیز با به‌روز رسانی نسخه‌ی جاوااسکریپت، ظاهرا مجبورند تا هسته‌ی فریم ورک‌های خود را یک آب و جاروی اساسی کنند. البته AngularJs در نسخه‌های 1.X مشکلاتی داشته است که در نسخه‌ی 2.0 غالب آنها رفع خواهند شد. از طرفی این اتفاقات تنها شامل فریم‌ورک‌های مبتنی بر جاوا‌اسکریپت نمی‌شود و Twitter نیز قصد دارد تا نسخه‌ی جدید Bootstrap را ارائه کند. چند وقتی هست که وب‌سایت رسمی Bootstrap در بالای صفحه‌ی اصلی خود پیغام Aww yeah, Bootstrap 4 is coming را مبنی بر آمدن نسخه‌ی 4 منتشر کرده است.
در این مقاله قصد داریم تا به بررسی امکانات Bootstrap 4 بپردازیم. اطلاعاتی که بنده قصد دارم در اختیار شما قرار دهم، مطالبی است که از چند بلاگ مانند وبلاگ رسمی Bootstrap برداشت شده است.
در ابتدای مطب معرفی Bootstrap 4 alpha این نوشته فروتنانه، شما را مجذوب خود خواهد کرد:
Bootstrap 4 در واقع یک اقدام بزرگ بود که پس از یک سال توسعه، بزرگی این اقدام در خط به خط کدها احساس می‌گردد. تصمیم گرفتیم تا نسخه‌ی اولیه‌ی آن را به اشتراک بگذاریم و انتقادات و پیشنهادات شما را بشنویم. برای بهبود و پیشرفت در این زمینه، بسیاری از اخبار مرتبط را در اختیار شما قرار می‌دهیم. امیدواریم که ما را در بهتر شدن یاری کنید.

امکانات جدید Bootstrap

انتقال از Less به Sass

در نسخه‌ی جدید، شما با استفاده از Sass قادر هستید تا بجای Less، کدهای استایل خود را به این صورت کامپایل و شخصی‌سازی نمایید. البته در Bootstrap 3 این امکان وجود نداشت ولی به صورت جداگانه و البته رسمی منتشر و در GitHub قرار داده شده بود.

بهبود grid system مبتنی بر "rems"

استفاده از سیستم grid همچنان با همان syntax پیشین استفاده می‌شود، اما کمی تغییر در معماری آن حاصل شده است. به عنوان مثال شما هنوز هم قادر به پیاده سازی سیستم مبتنی بر 12 ستون با استفاده از grid، یا تغییر عرض صفحه با استفاده از container و یا سیستم nested rows هستید.
اما چیز جدیدی که اضافه شده در container و یا به نوعی تغییر کلی در گرید بندی بنا به سایز دستگاههای مختلف است. بگذارید با یک مثال ببینیم که کار جدید صورت گرفته به چه شکلی است. در این مثال در Codepen چگونگی تغییر فونت سایز و سپس تغییر container را مشاهده می‌کنید. تا کنون شما قطعا از px، em  و pt برای تغییر ابعاد استفاده کرده‌اید. در bootstrap 4 تمام این اندازه‌ها مبتنی بر واحدی با نام rem است. این مفهوم خیلی آسان و قابل درک است. به این صورت که با استفاده از rem، تمامی font-sizeها وابسته به root element خواهند شد. بنابراین اگر شما یک وب سایت مبتنی بر Bootstrap 4 را Inspect کنید، خواهید دید که HTML tag دارای فونت سایز 16px است و باقی تگ‌ها بر این مقیاس وابسته هستند. به عنوان مثال تگ p دارای فونت سایز 1em است، یعنی همان 16px. و یا تگ h1 به صورت زیر خواهد بود:
h1 { /* 16 * 2.5 = 40px */
}
شاید بتوان گفت که مهم‌ترین دلیل این حرکت، ساده‌تر کردن فرایند بزرگ و کوچک کردن scale برای دستگاه‌های مختلف است. شما به سادگی قادرید که HTML tag را به سایز کوچک‌تر یا بزرگ‌تر تغییر دهید تا تمامی محتویات نیز به همان مقدار تغییر کنند. البته این نکته قابل توجه است که این تغییر از px به واحد rem تنها شامل font-sizeها نبوده و شامل تمامی scalingها مانند margin، padding و ... نیز می‌شود.

تغییر panel و wells به cards

در Bootstrap جدید، مجموعه‌ی پنل‌ها و wellها به یک ساختار جامع‌تر به نام Cards تبدیل گشته‌اند. این مجموعه به عنوان یک container محتویات که هم قابل انعطاف و هم قابل توسعه است معرفی شده است. همانطور که در اسناد مربوط به این مجموعه مشاهده می‌کنید، چندین مجموعه مانند list box‌ها و thumbnailها نیز در Card قرار گرفته‌اند. در این مجموعه، optionهای متفاوتی برای header و footer، و یا حالات متفاوت قرارگیری محتوا، حالت‌های مختلف back ground در نظر گرفته شده است.

Reset Component جایگزینی برای normalize.css

قبلا Bootstrap از Normalize.css جهت reset کردن محتویات css خود استفاده می‌کرد. Normalize در حقیقت یک مجموعه از قوانین CSS مینیفای شده است که تمامی استایل‌های پیش‌فرض مرورگر‌ها را به یک حالت پایدار reset می‌کند. معمولا همه‌ی مرورگر‌ها یک stylesheet از پیش تعریف شده‌ای دارند که برای وب‌سایت‌هایی که هیچ استایلی ندارند معمولا قابل مشاهده است. به عنوان مثال غالب مرورگرها به صورت پیش‌فرض لینک‌ها را به صورت آبی رنگ با underline نمایش می‌دهند و اینکه یک border خاص به جداول می‌دهند. با استفاده از css reset ها، تمامی استایل‌های از پیش تعیین شده‌ی مرورگرها null می‌شوند. این قابلیت به ما کمک می‌کند که راحت‌تر بتوانیم یک صفحه‌ی cross-browser ایجاد نماییم.
حال اینکه در Bootstrap جدید نوعی دیگر جایگزین Normalize شده است که reboot نام نهاده شده و محتویات آن در GitHub  موجود است. به نوعی می‌توان گفت که یک سری base style و resetها در این یک فایل ریخته شده که reboot نام دارد. این امر می‌تواند کمک بسیاری در Customize کردن موارد توسط خود توسعه دهنده کند.
ادامه دارد...
مطالب
استفاده از Unity در پیاده سازی الگوی Service locator
یکی از راهکارهای پیاده سازی IOC یا همان Inversion Of Control در پروژه‌های MVC استفاده از Unity و معرفی آن به DependencyResolver خود دات نت است.
برای آشنایی با Unity و قابلیت‌های آن میتوانید به اینجا و اینجا سر بزنید.
اما برای استفاده از Unity در پروژه‌های MVC کافی است در Global یا فایل راه انداز (bootstrapper ) تک تک انتزاع‌ها (Interface) را به کلاس‌های مرتبط شان معرفی کنید.
var container = new UnityContainer();  
container.RegisterType<ISomeService, SomeService>(new PerRequestLifetimeManager());
container.RegisterType<ISomeBusiness, SomeBusiness>(new PerRequestLifetimeManager());
container.RegisterType<ISomeController, SomeController>(new PerRequestLifetimeManager());
و بعد از ایجاد container از نوع UnityContainer میتوانیم آنرا به MVC معرفی کنیم:
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
تا به اینجا به‌راحتی میتوانید از سرویس‌های معرفی شده در پروژه MVC استفاده کنید.
var someService=(ISomeService)DependencyResolver.Current.GetService(typeof(ISomeService));
var data=someService.GetData();
اما اگر بخواهیم از کلاس‌های معرفی شده در Unity در لایه‌های دیگر (مثلا Business) استفاده کنیم چه باید کرد؟
برای هر این مشکل راهکارهای متفاوتی وجود دارد. من در لایه سرویس از Service locator بهره برده ام. برای آشنایی با این الگو اینجا را بخوانید. اکثر برنامه نویسان الگوهای IOC و Service Locator را با هم اشتباه میگیرند یا آنها را اشتباها بجای هم بکار میبرند.
برای درک تفاوت الگوی IOC و Service locator اینجا را بخوانید.

در لایه سرویس یک کلاس Service Factory داریم که قرار است همه سرویس‌ها، برای برقراری ارتباط با یکدیگر از آن استفاده کنند.این کلاس معمولا در لایه سرویس به اشکال گوناگونی پیاده سازی میشود که کارش وهه سازی از Interface‌های درخواستی است. اما برای یکپارچه کردن آن با Unity من آنرا به شکل زیر پیاده سازی کرده ام

public class ServiceFactory : MarshalByRefObject
    {
        static IUnityContainer uContainer = new UnityContainer();
        public static Type DataContextType { get; set; }

        public static void Initialise(IUnityContainer unityContainer, Type dbContextType)
        {
            uContainer = unityContainer;
            DataContextType = dbContextType;
            uContainer.RegisterType(typeof(BaseDataContext), DataContextType, new HierarchicalLifetimeManager());
        }
        public static T Create<T>()
        {
            return (T)Activator.CreateInstance<T>();
        }
        public static T Create<T>(string fullTypeName)
        {
            return (T)System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(fullTypeName);
        }
        public static T Create<T>(Type entityType)
        {
            return (T)Activator.CreateInstance(entityType);
        }
        public static dynamic Create(Type entityType)
        {
            return Activator.CreateInstance(entityType);
        }

        public static T Get<T>()
        {
            return uContainer.Resolve<T>();
        }
        public static object Get(Type type)
        {
            return uContainer.Resolve(type);
        }
    }

در این کلاس ما بجای ایجاد داینامیک آبجکت‌ها، از Unity استفاده کرده‌ایم. در همان ابتدا که برنامه‌ی وب ما برای اولین بار اجرا میشود و بعد از Register کردن کلاس‌ها، می‌توانیم container را به صورت پارامتر سازنده به کلاس Service Factory ارسال کنیم. به این ترتیب برای استفاده از سرویس‌ها در لایه Business از Unity بهره میبریم.

البته استفاده از Unity برای DataContext خیلی منطقی نیست و بهتر است نوع DataContext را در ابتدا بگیریم و هرجا نیاز داشتیم با استفاده از متد Create از آن وهله سازی بکنیم.