اشتراک‌ها
آموزش Microservices و Docker در NET Core.

Book cover

این آموزش کاملترین آموزش ماکروسافت برای توسعه برنامه‌های مبتنی بر معماری Microservices و مدیریت آنها با استفاده از Docker Containers در NET Core. است. 

برای یادگیری بهتر می‌توانید پروژه eShopOnContainers   که بر اساس مفاهیم این آموزش نوشته شده است را بررسی کنید.

لینک دانلود کتاب به صورت PDF 

آموزش Microservices و Docker در NET Core.
نظرات مطالب
کار با Docker بر روی ویندوز - قسمت دوم - نصب Docker
زمانیکه Hyper-V را در Windows 10 فعال میکنم،  VMWare اجرا میشه ولی هیچکدام از ماشینها رو اجرا نمیکنه و این خطا رو میده

 آیا برای رفع آن (به غیر از غیر فعال کردن Hyper-V ) راهی وجود داره که همزمان هم Docker، هم  VMWare  فعال باشند.
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 19 - بومی سازی
من مطابق موارد گفته شده و با توجه به امکانات  DataAnnotations  فرهنگ جاری رو تغییر میدم اما با توجه به ذکر دستور زیر
   opts.DefaultRequestCulture = new RequestCulture(culture: "fa-IR", uiCulture: "fa-IR");
متاسفانه در زمان اجرای پروژه و موجود نبودن کوکی فرهنگ en-US برگردانده میشود و پس از فراخوانی کنترلر تغییر زبان کوکی به فارسی برگردانده میشود و مشکل حل میشود. ولی متاسفانه در صورت نبود کوکی Default Culture انگیسی است البته با توجه به اینکه از Distibuted sql cache و Identity استفاده میکنم چطور میتونم این مشکل رو در پروژه‌ها حل کنیم؟  
مطالب
آشنایی با LibMan در پروژه‌های ASP.NET Core
مدیریت پکیج‌های سمت کلاینت
پروژه‌های جدیدی که با استفاده از قالب پیش‌فرض ایجاد می‌شوند، شامل یک پوشه با نام lib، در شاخه‌ی wwwroot هستند که حاوی این فایل‌ها می‌باشند:


اینها به عنوان حداقل‌های ایجاد یک وب اپلیکیشن، برای قالب انتخاب شده در نظر گرفته شده‌اند. اما فرض کنید بعد از مدتی می‌خواهیم ورژن bootstrap استفاده شده در پروژه را ارتقاء دهیم؛ در این حالت چندین انتخاب داریم:

  • دانلود مستقیم فایل موردنیاز و جایگزین کردن آن با نسخه‌ی فعلی
  • حذف پوشه‌ی wwwroot/lib و نصب مجدد پوشه‌ها از طریق NPM یا Yarn
  • استفاده از bower و سفارشی‌سازی مسیر قرار گرفتن فایل‌ها توسط browerrc.

روش اول، به نسبت ساده‌تر است؛ اما مشکل اینجاست که همه چیز به صورت دستی انجام خواهد گرفت. یعنی برای نسخه‌های بعدی همین روال باید مجدداً انجام شود. در روش دوم نیز مشکل اینجاست که مسیر قرار گرفتن پکیج‌های پروژه، از این به بعد node_modules خواهند بود و نیاز به یک تنظیم اضافی در فایل Startup.cs و مطلع کردن ASP.NET Core برای serve کردن فایل‌های سمت کلاینت است همچنین نیاز خواهد بود که تمامی ارجاعات داخل فایل Layout.cshtmlـ نیز از lib به node_modules تغییر پیدا کنند. در نهایت روش آخر نیز به دلیل منسوخ شدن bower پیشنهاد نمی‌شود.

استفاده از LibMan 
LibMan یک قابلیت جدید است که از نسخه‌ی Visual Studio 2017 برای مدیریت پکیج‌های سمت کلاینت اضافه شده است. این ابزار به صورت cross platform تهیه شده است؛ یعنی در خارج از Visual Studio نیز قابل استفاده می‌باشد. در واقع این ابزار را می‌توانیم به صورت Globally روی سیستم خود نصب کنیم و از طریق خط فرمان همانند NPM از آن استفاده کنیم.  

نصب و استفاده از LibMan
این ابزار ابتدا توسط Mads Kristensen با عنوان Client-Side Library Installer به صورت یک افزونه برای Visual Studio 2015 توسعه داده شد که در نهایت تیم ASP.NET این ابزار را  به صورت توکار به Visual Studio 2017 اضافه کرد. در نتیجه اگر از نسخه‌ی 2017 ویژوال استودیو استفاده می‌کنید، برای استفاده از این ابزار نیاز به نصب پکیج خاصی نخواهید داشت. برای استفاده از این ابزار در سیستم‌عامل‌های به غیر از ویندوز نیز یک CLI تهیه شده است که از طریق خط فرمان قابل استفاده می‌باشد. برای نصب این ابزار کافی است ابتدا آن را به صورت سراسری نصب کنید:
dotnet tool install -g Microsoft.Web.LibraryManager.Cli

قدم بعدی اضافه کردن فایلی با عنوان libman.json درون پروژه است. برای افزودن این فایل کافی است دستور زیر را در خطر فرمان وارد کنید:
libman init

با صدور فرمان فوق فایل مربوطه درون پروژه ایجاد می‌شود که در واقع یک فایل json ساده برای مدیریت پکیج‌های سمت کلاینت است:
{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": []
}

همانطور که مشاهده می‌کنید، می‌توانیم منبع دریافت پکیج‌‌ها را نیز تعیین کنیم که در حالت پیش‌فرض بر روی cdnjs تنظیم شده‌است و در واقع یک Content Delivery Network برای تعداد بیشماری پکیج سمت کلاینت است. درون آرایه‌ی libraries نیز می‌توانیم پکیج‌های موردنیاز خود را وارد کنیم. حتی برای هر پکیج هم می‌توانیم provider را override نمائیم. فرض کنید می‌خواهیم کتابخانه‌ی bootstrap را به پروژه اضافه کنیم. در اینحالت کافی است دستور زیر را برای نصب پکیج مربوطه صادر نمائیم:
libman install bootstrap@4.3.1 --provider unpkg --destination wwwroot/lib/bootstrap

در نهایت فایل libman.json چنین ساختاری پیدا خواهد کرد:
{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "provider": "unpkg",
      "library": "bootstrap@4.3.1",
      "destination": "wwwroot/lib/bootstrap"
    }
  ]
}

برای نصب مجدد پکیج هم می‌توانید از دستور libman restore استفاده کنید؛ در این حالت دقیقا مانند Nuget، پکیج‌ها از روی فایل libman.json از provider مربوطه دانلود و به پروژه اضافه خواهند شد. در ادامه لیست دستورات موجود را مشاهده می‌کنید:

مطالب
فعال سازی Multicore JIT
Multicore JIT یکی از قابلیت‌های کلیدی در دات نت 4.5 می‌باشد که در واقع راه حلی برای بهبود سرعت اجرای برنامه‌های دات نتی است. قبل از معرفی این قابلیت ابتدا اجازه دهید نحوه کامپایل یک برنامه دات نتی را بررسی کنیم.
انواع compilation
در حالت کلی دو نوع فرآیند کامپایل داریم:
  • Explicit
در این حالت دستورات قبل از اجرای برنامه به زبان ماشین تبدیل می‌شوند. به این نوع کامپایلرها AOT یا Ahead Of Time گفته می‌شود. این نوع از کامپایلرها برای اطمینان از اینکه CPU بتواند قبل از انجام تعاملی تمام خطوط کد را تشخیص دهد، طراحی شده اند.
  • Implicit
این نوع compilation به صورت دو مرحله ایی صورت می‌گیرد. در اولین قدم سورس کد توسط یک کامپایلر به یک زبان سطح میانی(IL) تبدیل می‌شود. در مرحله بعدی کد IL به دستورات زبان ماشین تبدیل می‌شوند. در دات نت فریم ورک به این کامپایلر JIT یا Just-In-Time گفته می‌شود.
در حالت دوم قابلیت جابجایی برنامه به آسانی امکان پذیر است، زیرا اولین قدم از فرآیند به اصطلاح platform agnostic می‌باشد، یعنی قابلیت اجرا بر روی گستره وسیعی از پلت فرم‌ها را دارد.

کامپایلر JIT
JIT بخشی از Common Language Runtime یا CLR می‌باشد. CLR در واقع وظیفه مدیریت اجرای تمام برنامه‌های دات نتی را برعهده دارد.

همانطور که در تصویر فوق مشاهده می‌کنید، سورس کد توسط کامپایلر دات نت به exe و یا dll کامپایل می‌شود. کامپایلر JIT تنها متدهایی را که در زمان اجرا(runtime) فراخوانی می‌شوند را کامپایل می‌کند. در دات نت فریم ورک سه نوع JIT Compilation داریم:

Normal JIT Compilation   

در این نوع کامپایل، متدها در زمان فراخوانی در زمان اجرا کامپایل می‌شوند. بعد از اجرا، متد داخل حافظه ذخیره می‌شود. به متدهای ذخیره شده در حافظه jitted گفته می‌شود. دیگر نیازی به کامپایل متد jit شده نیست. در فراخوانی بعدی، متد مستقیماً از حافظه کش در دسترس خواهد بود.

Econo JIT Compilation 

این نوع کامپایل شبیه به حالت Normal JIT است با این تفاوت که متدها بلافاصله بعد از اجرا از حافظه حذف می‌شوند.

Pre-JIT Compilation 

یکی دیگر از حالت‌های کامپایل برنامه‌های دات نتی Pre-JIT Compilation می باشد. در این حالت به جای متدهای مورد استفاده، کل اسمبلی کامپایل می‌شود. در دات نت می‌توان اینکار را توسط Ngen.exe یا (Native Image Generator) انجام داد. تمام دستورالعمل‌های CIL قبل از اجرا به کد محلی(Native Code) کامپایل می‌شوند. در این حالت runtime می‌تواند از native images به جای کامپایلر JIT استفاده کند. این نوع کامپایل عملیات تولید کد را در زمان اجرای برنامه به زمان Installation منتقل می‌کند، در اینصورت برنامه نیاز به یک Installer برای اینکار دارد.

Multicore JIT

در دات نت فریم ورک 4.5 یک راه حل جایگزین دیگر برای بهینه سازی و بهبود سرعت اجرای برنامه‌های دات نت وجود دارد. همانطور که عنوان شد Ngen.exe برای در دسترس بودن نیاز به Installer برای برنامه دارد. توسط Multicore JIT متدها بر روی دو هسته به صورت موازی کامپایل می‌شوند، در اینصورت می‌توانید تا 50 درصد از JIT Time صرفه جویی کنید.

Multicore JIT همچنین می‌تواند باعث بهبود سرعت در برنامه‌های WPF شود. در نمودار زیر می‌توانید حالت‌های استفاده و عدم استفاده از Multicore JIT را در سه برنامه WPF نوشته شده مشاهده کنید.

Multicore JIT در عمل

Multicore JIT از دو مد عملیاتی استفاده می‌کند: مد ثبت(Recording mode)، مد بازپخش(Playback mode)

در حالت ثبت کامپایلر JIT هر متدی که نیاز به کامپایل داشته باشد را رکورد می‌کند. بعد از اینکه CLR تعیین کند که اجرای برنامه به اتمام رسیده است، تمام متدهایی که اجرا شده اند را به صورت یک پروفایل بر روی دیسک ذخیره می‌کند.

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

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

استفاده از Multicore JIT

در برنامه‌های 4.5 ASP.NET و 5 Silverlight به صورت پیش فرض این ویژگی فعال می‌باشد. ازآنجائیکه این برنامه‌ها hosted application هستند؛ در نتیجه فضای مناسبی برای ذخیره سازی پروفایل در این نوع برنامه‌ها موجود می‌باشد. اما برای برنامه‌های Desktop این ویژگی باید فعال شود. برای اینکار کافی است دو خط زیر را به نقطه شروع برنامه تان اضافه کنید:

public App() 
{
    ProfileOptimization.SetProfileRoot(@"C:\MyAppFolder");
    ProfileOptimization.StartProfile("Startup.Profile");
}

توسط متد SetProfileRoot می‌توانیم مسیر ذخیره سازی پروفایل JIT را مشخص کنیم. در خط بعدی نیز توسط متد StartProfile نام پروفایل را برای فعال سازی Multicore JIT تعیین می‌کنیم. در این حالت در اولین اجرای برنامه پروفایلی وجود ندارد، Multicore JIT در حالت ثبت عمل می‌کند و پروفایل را در مسیر تعیین شده ایجاد می‌کند. در دومین بار اجرای برنامه CRL پروفایل را از اجرای قبلی برنامه بارگذاری می‌کند؛ در این حالت Multicore JIT به صورت بازپخش عمل می‌کند.

همانطور که عنوان شد در برنامه‌های ASP.NET 4.5 و Silverlight 5 قابلیت Multicore JIT به صورت پیش فرض فعال می‌باشد. برای غیر فعال سازی آن می‌توانید با تغییر فلگ profileGuidedOptimizations به None اینکار را انجام دهید:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
 <!-- ... -->
 <system.web> 
 <compilation profileGuidedOptimizations="None" /> 
 <!-- ... --> 
 </system.web> 
</configuration>
مطالب
پیاده سازی CQRS توسط MediatR - قسمت اول
در مطالب قبلی (1 , 2) الگوی CQRS معرفی شد. همانطور که می‌بینید، پیاده سازی این الگو هرچند با فریمورک آماده‌ای همچون SimpleCQRS، دارای پیچیدگی زیادی است و باعث نوشتن حجم زیادی کد می‌شود.

فریمورک MediatR توسط توسعه دهنده کتابخانه‌ی محبوب AutoMapper ایجاد شده‌است. این فریمورک پیاده سازی کاملی از الگوی طراحی Mediator در NET. است که داخل خود، تمام پیچیدگی‌های پیاده سازی CQRS را Abstract کرده و با حداقل کد ممکن، می‌توانید به‌راحتی CQRS را داخل پروژه‌ی خود پیاده سازی کنید.

در این سری مطالب به بررسی کامل الگوی CQRS و مزایا و معایب استفاده از آن می‌پردازیم و سپس با استفاده از کتابخانه‌ی Mediatr، این الگو را داخل یک پروژه پیاده سازی می‌کنیم.

CQRS

در CQRS متد‌های برنامه به 2 بخش Read و Write تقسیم می‌شوند. بخش‌هایی که State کلی برنامه ( شامل Database, Cookie, Session, LocalStorage, Memory و ... ) را تغییر می‌دهند، Command و بخش‌هایی که صرفا جنبه خواندنی دارند و وضعیت سیستم را تغییر نمی‌دهند مثل خواندن و نشان دادن اطلاعات از دیتابیس، Query می‌نامند.

* نکته : Naming Convention مورد استفاده برای Command‌‌ها به صورت دستوری است و کار Command در نام آن مشخص است؛ مثال : RegisterUser, SendForgottenPasswordEmail, PlaceOrder

مزایا:
1- شما می‌توانید تکنولوژی‌های مورد استفاده‌ی در بخش‌های Command و Query برنامه‌ی خود را به‌راحتی از هم جدا سازید. به‌عنوان مثال Apache Cassandra در ذخیره سازی داده‌ها ( Write Side ) به عنوان یک دیتابیس قابل اعتنا شناخته میشود و از طرفی دیگر ElasticSearch بدلیل سرعت فوق العاده‌ی خود، برای خواندن داده‌ها استفاده میشود. در این روش، دیتابیس‌ها باید Sync باشند تا داده‌های به‌روز به کاربر نمایش داده شود که این موضوع چالش‌های خود همچون Eventual Consistency و Strong Consistency را دارد که در مقالات بعدی آن‌ها را بررسی خواهیم کرد.

2- در برنامه‌های معمول، اکثرا بخش Read Side، بیشتر از Write Side استفاده می‌شود و کاربران معمولا اطلاعات را دریافت و می‌بینند تا اینکه در آن تغییری ایجاد کنند؛ در این صورت شما می‌توانید بخش Read برنامه‌ی خود را Scale کرده و تعداد سیستم یا منابع بیشتری را به این قسمت از برنامه‌ی خود اختصاص دهید ( Horizontal Scaling, Vertical Scaling ). 

3- این جداسازی باعث تمرکز بیشتر شما بر روی قسمت‌های مختلف برنامه می‌شود؛ بخش‌هایی که وضعیت سیستم را تغییر می‌دهند از بخش‌هایی که صرفا داده‌هایی را خوانده و نمایش می‌دهند، بطور کامل جدا شده‌اند و به‌راحتی قابلیت تغییر هرکدام از این بخش‌ها را خواهید داشت.

معایب : معمولا از معایب این الگو، از پیچیدگی پیاده سازی آن یاد می‌شود که در این آموزش با استفاده از Mediatr سعی بر از بین بردن این پیچیدگی را داریم.

Events

Event‌ها رویدادهایی هستند که خبر انجام کاری را که قبلا داخل سیستم انجامش به پایان رسیده است، به Consumer‌های خود می‌دهند. بعنوان مثال می‌خواهیم بعد از ثبت نام موفق یک کاربر داخل سیستم، Notification و یا ایمیلی را به او ارسال کنیم. بعد از ثبت نام کاربر میتوانیم Event ای به نام UserRegistered را که شامل Username و Email کاربر در بدنه خود است، Raise کنیم.

Event‌ها می‌توانند چندین Consumer داشته باشند؛ بنابراین می‌توانیم یک EventHandler را برای UserRegistered بنویسیم که Email ارسال کند و EventHandler دیگری ایجاد کنیم که Notification ای را برای کاربر بفرستد.

* نکته : Naming Convention مورد استفاده برای Event‌ها به صورت گذشته‌است و خبر یک کار، که قبلا انجام شده است را می‌دهد؛ مثال : UserRegistered, OrderPlaced

Event Sourcing

Event Sourcing به معنای ذخیره‌ی تمام Event‌های رخ داده در برنامه داخل یک دیتابیس Append-Only است. در این نوع دیتابیس‌ها فقط میتوانیم Event‌های جدیدی به آن اضافه کنیم و قادر به ویرایش و حذف Event‌ها نیستیم؛ چون منطق Event، کارهایی است که در گذشته اتفاق افتاده‌اند و ما قادر به تغییر چیزی که در گذشته رخ داده‌است، نیستیم.

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

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

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

* در این سری آموزشی از دیتابیس  Event Store برای پیاده سازی Event Sourcing استفاده خواهیم کرد.

در مقاله‌ی بعدی، امکانات فریمورک MediatR را بررسی خواهیم کرد.