مطالب
استفاده از چندین Context در EF 6 Code first
در نگارش قبلی EF Code first به ازای یک پروژه تنها یک سیستم Migration قابل تعریف بود و این سیستم مهاجرت، تنها با یک DbContext کار می‌کرد. در نگارش ششم این کتابخانه، سیستم مهاجرت Code first آن از چندین DbContext، به ازای یک پروژه که به یک بانک اطلاعاتی اشاره می‌کنند، پشتیبانی می‌کند. مزیت اینکار اندکی بهبود در نگهداری تنها کلاس DbContext تعریف شده است. برای مثال می‌توان یک کلاس DbContext مخصوص قسمت ثبت نام را ایجاد کرد. یک کلاس DbContext مخصوص کلیه جداول مرتبط با مقالات را و همینطور الی آخر. نهایتا تمام این Contextها سبب ایجاد یک بانک اطلاعاتی واحد خواهند شد.
اگر در یک پروژه EF Code first چندین Context وجود داشته باشد و دستور enable-migrations را بدون پارامتری فراخوانی کنیم، پیغام خطای More than one context type was found in the assmbly xyz را دریافت خواهیم کرد.
الف) اما در EF 6 می‌توان با بکار بردن سوئیچ جدید ContextTypeName، به ازای هر Context، مهاجرت مرتبط با آن‌را تنظیم نمود:
 enable-migrations -ContextTypeName dbContextName1 -MigrationDirectory DataContexts\Name1Migrations
همچنین در اینجا نیز می‌توان با استفاده از سوئیچ MigrationDirectory، فایل‌های تولید شده را در پوشه‌های مجزایی ذخیره کرد.

ب) در مرحله بعد، نیاز به فراخوانی دستور add-migration است:
 add-migration -ConfigurationTypeName FullNameSpaceCtx1.Configuration "InitialCreate"
با اجرای دستور enable-migrations یک کلاس Configuration جهت DbContext مشخص شده، ایجاد می‌شود. سپس آدرس کامل این کلاس را به همراه ذکر دقیق فضای نام آن در اختیار دستور add-migration قرار می‌دهیم.
ذکر کامل فضای نام، از این جهت مهم است که کلاس Configuration به ازای Contextهای مختلف ایجاد شده، یک نام را خواهد داشت؛ اما در فضاهای نام متفاوتی قرار می‌گیرد.
با اجرای دستور add-migration، کدهای سی شارپ مورد نیاز جهت اعمال تغییرات بر روی ساختار بانک اطلاعاتی تولید می‌شوند. در مرحله بعد، این کدها تبدیل به دستورات SQL متناظری شده و بر روی بانک اطلاعاتی اجرا خواهند شد.
بدیهی است اگر دو Context در برنامه تعریف کرده باشید، دوبار باید دستور enable-migrations و دوبار دستور add-migration را با پارامترهای اشاره کننده به Conetxtهای مدنظر اجرا کرد.

ج) سپس برای اعمال این تغییرات، باید دستور update-database را اجرا کرد.
 update-database  -ConfigurationTypeName FullNameSpaceCtx1.Configuration
اینبار دستور update-database نیز بر اساس نام کامل کلاس Configuration مدنظر باید اجرا گردد و به ازای هر Context موجود، یکبار نیاز است اجرا گردد.
نهایتا اگر به بانک اطلاعاتی مراجعه کنید، تمام جداول و تعاریف را یکجا در همان بانک اطلاعاتی می‌توانید مشاهده نمائید.


داشتن چندین Context در برنامه و مدیریت تراکنش‌ها

در EF، هر DbContext معرف یک واحد کار است. یعنی تراکنش‌ها و چندین عمل متوالی مرتبط انجام شده، درون یک DbContext معنا پیدا می‌کنند. متد SaveChanges نیز بر همین اساس است که کلیه اعمال ردیابی شده در طی یک واحد کار را در طی یک تراکنش به بانک اطلاعاتی اعمال می‌کند. همچنین مباحثی مانند lazy loading نیز در طی یک Context مفهوم دارند. به علاوه دیگر امکان join نویسی بین دو Context وجود نخواهد داشت. باید اطلاعات را از یکی واکشی و سپس این اطلاعات درون حافظه‌ای را به دیگری ارسال کنید.

یک نکته
می‌توان یک DbSet را در چندین ‍Context تعریف کرد. یعنی اگر بحث join نویسی مطرح است، با تکرار تعریف DbSetها اینکار قابل انجام است اما این مساله اساس جداسازی Contextها را نیز زیر سؤال می‌برد.
 

داشتن چندین Context در برنامه و مدیریت رشته‌های اتصالی

در EF Code first روش‌های مختلفی برای تعریف رشته اتصالی به بانک اطلاعاتی وجود دارند. اگر تغییر خاصی در کلاس مشتق شده از DbContext ایجاد نکنیم، نام کلید رشته اتصالی تعریف شده در فایل کانفیگ باید به نام کامل کلاس Context برنامه اشاره کند. اما با داشتن چندین Context به ازای یک دیتابیس می‌توان از روش ذیل استفاده کرد:

  public class Ctx1 : DbContext
    {
        public Ctx1()
            : base("DefaultConnection")
        {
            //Database.Log = sql => Debug.Write(sql);
        }
    }

  public class Ctx2 : DbContext
    {
        public Ctx2()
            : base("DefaultConnection")
        {
            //Database.Log = sql => Debug.Write(sql);
        }
    }

  <connectionStrings>
    <add name="DefaultConnection" connectionString="…." providerName="System.Data.SqlClient" />
  </connectionStrings>
در اینجا در سازنده کلاس‌های Context تعریف شده، نام کلید رشته اتصالی موجود در فایل کانفیگ برنامه ذکر شده است. به این ترتیب این دو Context به یک بانک اطلاعاتی اشاره خواهند کرد.


چه زمانی بهتر است از چندین Context در برنامه استفاده کرد؟
عموما در طراحی‌های سازمانی SQL Server، تمام جداول از schema مدیریتی به نام dbo استفاده نمی‌کنند. جداول فروش از schema خاص خود و جداول کاربران از schema دیگری استفاده خواهند کرد. با استفاده از چندین Context می‌توان به ازای هر کدام از schemaهای متفاوت موجود، «یک ناحیه ایزوله» را ایجاد و مدیریت کرد.
  public class Ctx2 : DbContext
    {
        public Ctx2()
            : base("DefaultConnection")
        {
            //Database.Log = sql => Debug.Write(sql);
        }

         protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("sales");
            base.OnModelCreating(modelBuilder);
        }
    }
در این حالت در EF 6 می‌توان DefaultSchema کلی یک Context را در متد بازنویسی شده OnModelCreating به نحو فوق تعریف و مدیریت کرد. در این مثال به صورت خودکار کلیه DbSetهای Ctx2 از schema ایی به نام sales استفاده می‌کنند.
نظرات مطالب
Protocol Buffers فرمتی برای تبادل دیتا
مقاله جالب و خوبی بود فقط ذکر چند نکته خالی از لطف نیست.
protobuf در مرورگر پشتیبانی نمی‌شود و برای کار با آن می‌توان از  protobuf.js (پیاده سازی Protocol Buffers برای Javascript) استفاده کرد 
برای استفاده از protobuf در دات نت نیز 2 کتابخانه موجود است
1- کتابخانه  Google.Protobuf : که پیاده سازی و استفاده از آن شبیه نسخه اصلی protobuf است. (اطلاعات بیشتر)
2- کتابخانه  protobuf-net : که پیاده سازی و استفاده از آن شبیه بقیه سریالایزر‌های دات نتی بوده و بیشتر متمایل به سی شارپ است. (اطلاعات بیشتر)
به نظرم دومی بیشتر باب میل سی شارپی‌ها باشد و نیز ساده تر. با دیدن مثال هر دو کتابخانه میتوانید بهتر متوجه این تفاوت شوید.
لینک زیر هم به مقایسه این دو کتابخانه پرداخته : 
مطالب
Angular CLI - قسمت پنجم - ساخت و توزیع برنامه
ساخت و توزیع برنامه‌های Angular یکی از مهم‌ترین و بحث برانگیزترین قسمت‌های نگارش‌های جدید آن است و به ازای هر پروژه و قالبی که برای آن توسط گروه‌های مختلف ارائه شده‌است، روش‌های متفاوتی را شاهد خواهید بود. در ادامه روش توصیه شده‌ی توسط تیم Angular را که مبتنی است بر webpack و به صورت خودکار توسط Angular CLI مدیریت می‌شود، بررسی خواهیم کرد.


ساخت (Build) برنامه‌های Angular

Angular CLI کار ساخت و کامپایل برنامه را به صورت خودکار انجام داده و خروجی را در مسیری مشخص درج می‌کند. در اینجا می‌توان گزینه‌هایی را بر اساس نوع کامپایل مدنظر مانند کامپایل برای حالت توسعه و یا کامپایل برای حالت توزیع نهایی، انتخاب کرد. همچنین مباحث bundling و یکی کردن تعداد بالای ماژول‌های برنامه در آن لحاظ می‌شوند تا برنامه در حالت توزیع نهایی، سبب 100ها رفت و برگشت به سرور برای دریافت ماژول‌های مختلف آن نشود. به علاوه مباحث uglification (به نوعی obfuscation کدهای جاوا اسکریپتی نهایی) و tree-shaking (حذف کدهایی که در برنامه استفاده نشده‌اند؛ یا کدهای مرده) نیز پیاده سازی می‌شوند. با انجام tree-shaking‌، نه تنها اندازه‌ی توزیع نهایی به کاربر کاهش پیدا می‌کند، بلکه مرورگر نیز حجم کمتری از کدهای جاوااسکریپتی را باید تفسیر کند.
برای شروع می‌توان از دستور ذیل برای مشاهده‌ی تمام گزینه‌های مهیای ساخت برنامه استفاده کرد:
> ng build --help
ذکر تنهای دستور ng build‌، بدون هیچ گزینه‌ای، برای حالت «توسعه‌ی» برنامه بسیار ایده‌آل است (و دقیقا به معنای صدور دستور ng build --dev است). در این حالت خروجی کامپایل شده‌ی برنامه در پوشه‌ی dist تولید می‌شود. اگر از قسمت دوم این سری به خاطر داشته باشید، نام این پوشه‌ی خروجی، جزئی از تنظیمات فایل angular-cli.json. است:
"apps": [
{
   "outDir": "dist",
زمانیکه دستور ng build‌  صادر شود، این فایل‌ها را در پوشه‌ی dist خواهید یافت:

فایل 
توضیح 
 inline.bundle.js   WebPack runtime
از آن برای بارگذاری ماژول‌های برنامه و چسباندن قسمت‌های مختلف به یکدیگر استفاده می‌شود. 
 main.bundle.js   شامل تمام کدهای ما است. 
 polyfills.bundle.js   Polyfills - جهت پشتیبانی از مرورگرهای مختلف.
 styles.bundle.js    شامل بسته بندی تمام شیوه نامه‌های برنامه است 
vendor.bundle.js  کدهای کتابخانه‌های ثالث مورد استفاده و همچنین خود Angular، در اینجا بسته بندی می‌شوند. 
 

روشی برای بررسی محتوای bundleهای تولید شده

تولید bundleها در جهت کاهش رفت و برگشت‌های به سرور و بالا بردن کارآیی برنامه ضروری هستند؛ اما دقیقا این بسته بندی‌ها شامل چه اطلاعاتی می‌شوند؟ این اطلاعات را می‌توان از فایل‌های source map تولیدی استخراج کرد و برای این منظور می‌توان از برنامه‌ی source-map-explorer استفاده کرد.

روش نصب عمومی آن:
 > npm install -g source-map-explorer
روش اجرا:
 > source-map-explorer dist/main.bundle.js
پس از آن یک گزارش HTML ایی از محتوای bundle مدنظر تولید می‌شود.


یک مثال: ساخت برنامه‌ی مثال قسمت چهارم - تنظیمات مسیریابی در حالت dev

در ادامه، کار Build همان مثالی را که در قسمت قبل توضیح داده شد، بررسی می‌کنیم. برای این منظور از طریق خط فرمان به ریشه‌ی پوشه‌ی اصلی پروژه وارد شده و دستور ng build را صادر کنید. یک چنین خروجی را مشاهده خواهید کرد:
 D:\Prog\angular-routing>ng build
Hash: 123cae8bd8e571f44c31
Time: 33862ms
chunk {0} polyfills.bundle.js, polyfills.bundle.js.map (polyfills) 158 kB {4} [initial] [rendered]
chunk {1} main.bundle.js, main.bundle.js.map (main) 14.7 kB {3} [initial] [rendered]
chunk {2} styles.bundle.js, styles.bundle.js.map (styles) 9.77 kB {4} [initial] [rendered]
chunk {3} vendor.bundle.js, vendor.bundle.js.map (vendor) 2.34 MB [initial] [rendered]
chunk {4} inline.bundle.js, inline.bundle.js.map (inline) 0 bytes [entry] [rendered]
و اگر فایل index.html تولیدی آن‌را بررسی کنید، تنها الحاق همین 4 فایل js تولیدی را مشاهده می‌نمائید:
<!doctype html>
<html>
<head>
  <meta charset="utf-8">
  <title>AngularRouting</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
  <app-root>Loading...</app-root>
<script type="text/javascript" src="inline.bundle.js">
</script><script type="text/javascript" src="polyfills.bundle.js">
</script><script type="text/javascript" src="styles.bundle.js">
</script><script type="text/javascript" src="vendor.bundle.js">
</script><script type="text/javascript" src="main.bundle.js"></script>
</body>
</html>

یک نکته: زمانیکه دستور ng serve -o صادر می‌شود، در پشت صحنه دقیقا همین دستور ng build صادر شده و اطلاعات را درون حافظه تشکیل می‌دهد. اما اگر کار ng build را دستی انجام دهیم، اینبار ng serve -o اطلاعات را از پوشه‌ی dist دریافت می‌کند. بنابراین در حین کار با ng serve -o نیازی به build دستی پروژه نیست.

سؤال: چرا حجم فایل endor.bundle.js اینقدر بالا است و شامل چه اجزایی می‌شود؟
نکته‌ای که در اینجا وجود دارد، حجم بالای فایل vendor.bundle.js آن است که 2.34 MB می‌باشد:


چون دستور ng build بدون پارامتری ذکر شده‌است، برنامه را برای حالت توسعه Build می‌کند و به همین جهت هیچگونه بهینه سازی در این مرحله صورت نخواهد گرفت. برای بررسی محتوای این فایل می‌توان دستور ذیل را در ریشه‌ی اصلی پروژه صادر کرد:
 > source-map-explorer dist/vendor.bundle.js
پس از اجرای این دستور، بلافاصله مرورگر پیش فرض سیستم اجرا شده و گزارشی را ارائه می‌دهد.


همانطور که مشاهده می‌کنید، در حالت بهینه سازی نشده و Build برای توسعه، کامپایلر Angular حدود 41 درصد حجم فایل vendor.bundle.js را تشکیل می‌دهد. به علاوه ماژول‌ها و قسمت‌هایی را ملاحظه می‌کنید که اساسا برنامه‌ی فعلی مثال ما از آن‌ها استفاده نمی‌کند؛ مانند http، فرم‌ها و غیره.


سفارشی سازی Build برای محیط‌های مختلف

اگر به پروژه‌ی تولید شده‌ی توسط Angular CLI دقت کنید، حاوی پوشه‌ای است به نام src\environments


هدف از فایل‌های environment برای نمونه تغییر آدرس توزیع برنامه در حالت توسعه و ارائه نهایی است.
همچنین در اینجا می‌توان نحوه‌ی بهینه سازی فایل‌های تولیدی را توسط Build Targets مشخص کرد و اینکار توسط ذکر پرچم prod-- (مخفف production) صورت می‌گیرد.
در ادامه، تفاوت‌های دستورهای ng build و ng build --prod را ملاحظه می‌کنید:
- با اجرای ng build، از فایل environment.ts استفاده می‌شود؛ برخلاف حالت اجرای ng build --prod که از فایل environment.prod.ts استفاده می‌کند.
- Cache-busting در حالت ارائه‌ی نهایی، به تمام اجزای پروژه اعمال می‌شود؛ اما در حالت توسعه فقط برای تصاویر قید شده‌ی در فایل‌های css.
- فایل‌های source map فقط برای حالت توسعه تولید می‌شوند.
- در حالت توسعه، cssها داخل فایل‌های js تولیدی قرار می‌گیرند؛ اما در حالت ارائه‌ی نهایی به صورت فایل‌های css بسته بندی می‌شوند.
- در حالت توسعه برخلاف حالت ارائه‌ی نهایی، کار uglification انجام نمی‌شود.
- در حالت توسعه برخلاف حالت ارائه‌ی نهایی، کار tree-shaking یا حذف کدهای مرده و بدون ارجاع، انجام نمی‌شود.
- در حالت توسعه برخلاف حالت ارائه‌ی نهایی، کار AOT انجام نمی‌شود. در اینجا AOT به معنای Ahead of time compilation است.
- در هر دو حالت توسعه و ارائه‌ی نهایی کار bundling و دسته بندی فایل‌ها انجام خواهد شد.

به همین جهت است که ng build سریع است؛ اما حجم بالاتری را هم تولید می‌کند. چون بسیاری از بهینه سازی‌های حالت ارائه‌ی نهایی را به همراه ندارد.


دستورات build برای حالت توسعه و ارائه‌ی نهایی

برای حالت توسعه، هر 4 دستور ذیل یک مفهوم را دارند و به همین جهت مورد ng build متداول‌تر است:
>ng build --target=development --environment=dev
>ng build --dev -e=dev
>ng build --dev
>ng build

برای حالت ارائه‌ی نهایی، هر 3 دستور ذیل یک مفهوم را دارند و به همین جهت مورد ng build --prod متداول‌تر است:
>ng build --target=production --environment=prod
>ng build --prod -e=prod
>ng build --prod

همچنین هر کدام از این دستورات را توسط پرچم‌های ذیل نیز می‌توان سفارشی سازی کرد:

 پرچم  مخفف  توضیح
 sourcemap--  sm-  تولید سورس‌مپ
aot--    Ahead of Time compilation 
watch--  w-  تحت نظر قرار دادن فایل‌ها و ساخت مجدد
environment--  e-  محیط ساخت
 target--  t-  نوع ساخت
 dev--    مخفف نوع ساخت جهت توسعه
 prod--     مخفف نوع ساخت جهت ارائه نهایی

برای مثال در حالت prod، سورس‌مپ‌ها تولید نخواهند شد. اگر علاقمندید تا این فایل‌ها نیز تولید شوند، پرچم souremap را نیز ذکر کنید.
و یا اگر برای حالت dev می‌خواهید AOT را فعالسازی کنید، پرچم aot-- را در آنجا قید کنید.


یک مثال: ساخت برنامه‌ی مثال قسمت چهارم - تنظیمات مسیریابی در حالت prod

تا اینجا خروجی حالت dev ساخت برنامه‌ی قسمت چهارم را بررسی کردیم. در ادامه دستور ng build --prod را در ریشه‌ی پروژه صادر می‌کنیم:
 D:\Prog\angular-routing>ng build --prod
Hash: f5bd7fd555a85af8a86f
Time: 39932ms
chunk {0} polyfills.18173234f9641113b9fe.bundle.js (polyfills) 158 kB {4} [initial] [rendered]
chunk {1} main.c6958def7c5f51c45261.bundle.js (main) 50.3 kB {3} [initial] [rendered]
chunk {2} styles.d41d8cd98f00b204e980.bundle.css (styles) 69 bytes {4} [initial] [rendered]
chunk {3} vendor.b426ba6883193375121e.bundle.js (vendor) 1.37 MB [initial] [rendered]
chunk {4} inline.8cec210370dd3af5f1a0.bundle.js (inline) 0 bytes [entry] [rendered]


همانطور که ملاحظه می‌کنید، اینبار نه تنها حجم فایل‌ها به میزان قابل ملاحظه‌ای کاهش پیدا کرده‌اند، بلکه این نام‌ها به همراه یک سری hash هم هستند که کار cache-busting (منقضی کردن کش مرورگر، با ارائه‌ی نگارشی جدید) را انجام می‌دهند.

در ادامه اگر بخواهیم مجددا برنامه‌ی source-map-explorer را جهت بررسی محتوای فایل‌های js اجرا کنیم، به خطای عدم وجود sourcemapها خواهیم رسید (چون در حالت prod، به صورت پیش فرض غیرفعال هستند). به همین‌جهت برای این مقصود خاص نیاز است از پرچم فعالسازی موقت آن استفاده کرد:
> ng build --prod --sourcemap
> source-map-explorer dist/vendor.b426ba6883193375121e.bundle.js


همانطور که در تصویر نیز مشخص است، اینبار کامپایلر Angular به همراه تمام ماژول‌هایی که در برنامه ارجاعی به آن‌ها وجود نداشته‌است، حذف شده‌اند و کل حجم بسته‌ی Angular به 366 KB کاهش یافته‌است.


بررسی دستور ng serve

تا اینجا برای اجرای برنامه در حالت dev از دستور ng serve -o استفاده کرده‌ایم. کار ارائه‌ی برنامه توسط این دستور، از محتوای کامپایل شده‌ی درون حافظه با مدیریت webpack انجام می‌شود. به همین جهت بسیار سریع بوده و قابلیت live reload را ارائه می‌دهد (نمایش آنی تغییرات در مرورگر، با تغییر فایل‌ها).
همانند تمام دستورات دیگر، اطلاعات بیشتری را در مورد این دستور، از طریق راهنمای آن می‌توان به دست آورد:
 > ng serve --help

که شامل این موارد هستند (علاوه بر تمام مواردی را که در حالت ng build می‌توان مشخص کرد؛ مثلا ng serve --prod -o):

 پرچم مخفف
توضیح
 open-- o-
بازکردن خودکار مرورگر پیش فرض.
حالت پیش فرض آن گشودن مرورگر توسط خودتان است و سپس مراجعه‌ی دستی به آدرس برنامه. 
 port--  p-  تغییر پورت پیش فرض مانند ng server -p 8626 
 live-reload--  lr-   فعال است مگر اینکه آن‌را با false مقدار دهی کنید.
 ssl--    ارائه به صورت HTTPS
 proxy-config--  pc-  Proxy configuration file 


استخراج فایل تنظیمات webpack از Angular CLI

Angular CLI برای مدیریت build، در پشت صحنه از webpack استفاده می‌کند. فایل تنظیمات آن نیز جزئی از فایل‌های توکار این ابزار است و قرار نیست به صورت پیش فرض و مستقیم توسط پروژه‌ی جاری ویرایش شود. به همین جهت آن‌را در ساختار پروژه‌ی تولید شده، مشاهده نمی‌کنید.
اگر علاقمند به سفارشی سازی بیشتر این تنظیمات پیش فرض باشید، ابتدا باید آن‌را اصطلاحا eject کنید و سپس می‌توان آن‌را ویرایش کرد:
 > ng eject
Ejection was successful.

To run your builds, you now need to do the following commands:
- "npm run build" to build.
- "npm run test" to run unit tests.
- "npm start" to serve the app using webpack-dev-server.
- "npm run e2e" to run protractor.

Running the equivalent CLI commands will result in an error.
============================================
Some packages were added. Please run "npm install".
همانطور که مشاهده می‌کنید عنوان کرده‌است که از این پس خودتان باید بسیاری از مسایل را به صورت دستی مدیریت کنید و Angular CLI دیگر آن‌ها را به صورت خودکار مدیریت نمی‌کند و دیگر دستورات ng build و ng serve کار نخواهند کرد (این تغییرات در فایل package.json درج می‌شوند).
در این حالت است که فایل webpack.config.js به ریشه‌ی پروژه جهت سفارشی سازی شما اضافه خواهد شد. همچنین فایل‌های .angular-cli.json، package.json نیز جهت درج این تغییرات ویرایش می‌شوند.

و اگر در این لحظه پشیمان شده‌اید (!) فقط کافی است تا این مرحله‌ی جدید commit شده‌ی به مخزن کد را لغو کنید و باز هم به همان Angular CLI قبلی می‌رسید.
مطالب دوره‌ها
مثال‌هایی بیشتر از عملکرد پشته‌ای MSIL
بررسی عملکرد و کدهای IL یک متد

        ldarg.0
        stloc_0
L_0000:
        ldloc_0
        ldc_i4 5
        add
        stloc_0
        ldloc_0
        ldc_i4 15
        blt L_0000
        ldloc_0
        ret
به کدهای IL فوق دقت کنید. در ادامه قصد داریم عملکرد این متد را بررسی کرده و سپس سعی کنیم تا معادل سی شارپ آن‌را حدس بزنیم. (البته سعی کنید طوری مطلب را مطالعه کنید که ادامه بحث را در ابتدا مشاهده نکنید!)
این متد، یک مقدار int را دریافت کرده و با انجام محاسباتی بر روی آن، مقدار int دیگری را بازگشت می‌دهد.
کار با ldarg.0 شروع می‌شود. به این ترتیب آرگومان موجود در ایندکس صفر، بر روی پشته بارگذاری خواهد شد. فرض کنید ورودی 5 را به این متد ارسال کرده‌ایم.
سپس stloc_0 این مقدار را از پشته pop کرده و در یک متغیر محلی ذخیره می‌کند.
در ادامه برچسب L_0000 تعریف شده است. از برچسب‌ها برای انتقال جریان اجرایی برنامه استفاده می‌کنیم.
ldloc_0 به معنای بارگذاری متغیر محلی از ایندکس صفر است. به این ترتیب عدد 5 بر روی پشته ارزیابی قرار می‌گیرد.
توسط ldc_i4 5، یک i4 یا int 32 بیتی یا int ایی با 4 بایت، به عنوان یک عدد ثابت بارگذاری می‌شود. این عدد نیز بر روی پشته ارزیابی قرار می‌گیرد.
در ادامه با فراخوانی Add، دو مقدار قرار گرفته بر روی پشته pop شده و نتیجه 10؛ مجددا بر روی پشته قرار می‌گیرد.
stloc_0 سبب می‌شود تا این عدد 10 در یک متغیر محلی در ایندکس صفر ذخیره شود.
با فراخوانی ldloc_0، این متغیر محلی به پشته ارزیابی منتقل می‌شود.
به کمک ldc_i4 15، یک عدد صحیح 4 بایتی با مقدار ثابت 15 بارگذاری می‌شود.
در ادامه blt بررسی می‌کند که اگر 10 کوچکتر است از 15 ایی که بر روی پشته قرار گرفته، آنگاه جریان عملیات را به برچسب L_0000 منتقل می‌کند (پرش به برچسب صورت خواهد گرفت).
اگر با سایر زبان‌های اسمبلی کار کرده باشید با lt، gt و امثال آن به طور قطع آشنایی دارید. در اینجا blt به معنای branch less than equal است.
بنابراین در ادامه مجددا همین اعمال فوق تکرار خواهند شد تا به ارزیابی blt جهت دو مقدار 15 با 15 برسیم. از آنجائیکه اینبار 15 کوچکتر از 15 نیست، سطر پس از آن یعنی ldloc_0 اجرا می‌شود که معادل است با بارگذاری 15 به پشته ارزیابی و سپس return فراخوانی می‌شود تا این مقدار را بازگشت دهد.



خوب؛ آیا می‌توانید کدهای معادل سی‌شارپ آن‌را حدس بزنید؟!

        public static int Calculate(int x)
        {
            for (; x < 15; x += 5)
            {
            }
            return x;
        }
بله. متد محاسباتی که در ابتدای بحث کدهای IL آن‌را ملاحظه نمودید، یک چنین معادل سی‌شارپی دارد.


فراخوانی متدها در MSIL

برای فراخوانی متدها در کدهای IL از OpCode ایی به نام call استفاده می‌شود:
 ldstr "hello world"
call void [mscorlib]System.Console::WriteLine(string)
در این مثال توسط ldstr، یک رشته بارگذاری شده و سپس توسط call اطلاعات متدی که باید فراخوانی شود، ذکر می‌گردد. همانطور که ملاحظه می‌کنید، امضای کامل متد نیاز است ذکر گردد؛ متدی از نوع void قرار گرفته در mscorlib با ذکر فضای نام و نام متد مورد نظر.


بررسی یک الگوریتم بازگشتی در MSIL

ابتدا متد بازگشتی ذیل را درنظر بگیرید:
        public static int Calculate(int n)
        {
            if (n <= 1) return n;
            return n * Calculate(n - 1);
        }
اگر کد دی‌کامپایل شده‌ی آن را در ILSpy بررسی کنیم، به دستورات ذیل خواهیم رسید:
.method public hidebysig static 
int32 Calculate (
int32 n
) cil managed 
{
// Method begins at RVA 0x3c0d
// Code size 17 (0x11)
.maxstack 8

IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: bgt.s IL_0006

IL_0004: ldarg.0
IL_0005: ret

IL_0006: ldarg.0
IL_0007: ldarg.0
IL_0008: ldc.i4.1
IL_0009: sub
IL_000a: call int32 FastReflectionTests.Test::Calculate(int32)
IL_000f: mul
IL_0010: ret
} // end of method Test::Calculate
در اینجا ابتدا مقدار آرگومان متد، توسط ldarg بارگذاری می‌شود. سپس مقدار ثابت یک بارگذاری می‌شود. توسط bgt بررسی خواهد شد اگر مقدار آرگومان (عدد اول) بزرگتر است از مقدار عدد ثابت یک (عدد دوم)، آنگاه به برچسب IL_0006 پرش صورت گیرد و قسمت ضرب بازگشتی انجام شود. در غیراینصورت آرگومان متد بارگذاری شده و در سطر IL_0005 کار خاتمه می‌یابد.
در سطرهای IL_0006 و IL_0007، دوبار کار بارگذاری آرگومان متد انجام شده است؛ یکبار برای عملیات ضرب و بار دیگر برای عملیات تفریق از یک.
سپس عدد ثابت یک بارگذاری شده و از مقدار آرگومان، توسط sub کسر خواهد شد. در ادامه متد Calculate به صورت بازگشتی فراخونی می‌گردد. در این حالت دوباره به سطر IL_0000 هدایت خواهیم شد و عملیات ادامه می‌یابد.
نظرات مطالب
Lazy Loading در AngularJS
با تشکر.
اگر ممکن است یک نمونه از تعریف دایرکتیو توسط lazy را هم بنویسید.
اشتراک‌ها
parallel programing توی دلفی
احتمالا  Embarcadero از این برنامه نویسان استفاده کنه و کتابخانه هارو توی ورژن‌های بعدی بصورت VCL منتشر کنه.
Delphi never dies
parallel programing توی دلفی
نظرات مطالب
استفاده از RequireJs در پروژه های Asp.Net MVC
زمانیکه از آنگولار 2 به بالا استفاده میکنیم باز هم احتیاجی به این کتابخانه وجود داره؟
خود انگولار این ماجول‌ها رو در قالب کامپوننت درمیاره، یعنی مجبوریم بصورت کامپوننتهای جدا از هم دربیاریم
مطالب دوره‌ها
مدیریت تغییرات گریدی از اطلاعات به کمک استفاده از الگوی واحد کار مشترک بین ViewModel و لایه سرویس
قالب پروژه WPF Framework به همراه چندین صفحه ابتدایی لازم، برای شروع هر برنامه‌ی تجاری دسکتاپی است؛ مثال مانند صفحه لاگین، صفحه تغییرات مشخصات کاربر وارد شده به سیستم و امثال آن. صفحه‌ای را که در این قسمت بررسی خواهیم کرد، صفحه تعریف کاربران جدید و ویرایش اطلاعات کاربران موجود است.


در این صفحه با کلیک بر روی دکمه به علاوه، یک ردیف به ردیف‌های موجود اضافه شده و در اینجا می‌توان اطلاعات کاربر جدیدی به همراه سطح دسترسی او را وارد و ذخیره کرد و یا حتی اطلاعات کاربران موجود را ویرایش نمود. اگر بخواهیم مانند مراحلی که در قسمت قبل در مورد تعریف یک صفحه جدید در برنامه توضیح داده شد، عمل کنیم، به صورت خلاصه به ترتیب ذیل عمل شده است:
1) ایجاد صفحه تغییر مشخصات کاربر
ابتدا صفحه Views\Admin\AddNewUser.xaml به پروژه ریشه که Viewهای برنامه در آن تعریف می‌شوند، اضافه شده است. به همراه دو دکمه و یک ListView که تطابق بهتری با قالب متروی مورد استفاده دارد.

2) تنظیم اعتبارسنجی صفحه اضافه شده
مرحله بعد تعریف هر صفحه‌ای در سیستم، مشخص سازی وضعیت دسترسی به آن است:
/// <summary>
/// افزودن و مدیریت کاربران سیستم
/// </summary>
[PageAuthorization(AuthorizationType.ApplyRequiredRoles, "IsAdmin, CanAddNewUser")]
ویژگی PageAuthorization به فایل Views\Admin\AddNewUser.xaml.cs اعمال شده است. در اینجا تنها کاربرانی که خاصیت‌های IsAdmin و CanAddNewUser آن‌ها true باشند، مجوز دسترسی به صفحه تعریف کاربران را خواهند یافت.

3) تغییر منوی برنامه جهت اشاره به صفحه جدید
در ادامه در فایل منوی برنامه Views\MainMenu.xaml تعریف دسترسی به صفحه Views\Admin\AddNewUser.xaml قید شده است:
                <Button Style="{DynamicResource MetroCircleButtonStyle}"
                        Height="55" Width="55"  
                        Command="{Binding DoNavigate}"
                        CommandParameter="\Views\Admin\AddNewUser.xaml"
                        Margin="2">
                    <Rectangle Width="28" Height="17.25">
                        <Rectangle.Fill>
                            <VisualBrush Stretch="Fill" Visual="{StaticResource appbar_user_add}" />
                        </Rectangle.Fill>
                    </Rectangle>
                </Button>
همانطور که در قسمت قبل نیز توضیح داده شده، تنها کافی است در اینجا CommandParameter را مساوی مسیر فایل AddNewUser.xaml قرار دهیم تا سیستم راهبری به صورت خودکار از آن استفاده کند.

4) ایجاد ViewModel متناظر با صفحه
مرحله نهایی تعریف صفحه AddNewUser، افزودن ViewModel متناظر با آن است که سورس کامل آن‌را در فایل ViewModels\Admin\AddNewUserViewModel.cs پروژه Infrastructure می‌توانید ملاحظه کنید.
نکته مهم این ViewModel، ارائه خاصیت لیست کاربران از نوع ObservableCollection به View و گرید برنامه است:
public ObservableCollection<User> UsersList { set; get; }
اطلاعات آن از IUsersService تزریق شده در سازنده کلاس ViewModel دریافت می‌شود:
        /// <summary>
        /// جهت مقاصد انقیاد داده‌ها در دبلیو پی اف طراحی شده است
        /// لیستی از کاربران سیستم را باز می‌گرداند
        /// </summary>
        /// <param name="count">تعداد کاربر مد نظر</param>
        /// <returns>لیستی از کاربران</returns>
        public ObservableCollection<User> GetSyncedUsersList(int count = 1000)
        {
            _users.OrderBy(x => x.FriendlyName).Take(count)
                  .Load();

            // For Databinding with WPF.
            // Before calling this method you need to fill the context by using `Load()` method.
            return _users.Local;
        }
این کدها را در فایل UsersService.cs لایه سرویس برنامه می‌توانید مشاهده نمائید.
در اینجا از قابلیت خاصیتی به نام Local که یک ObservableCollection تحت نظر EF را بازگشت می‌دهد، استفاده شده است. برای استفاده از این خاصیت، ابتدا باید کوئری خود را تهیه و سپس متد Load را بر روی آن فراخوانی کرد. سپس خاصیت Local بر اساس اطلاعات کوئری قبلی پر و مقدار دهی خواهد شد.
علت انتخاب نام Synced برای این متد، تحت نظر بودن اطلاعات خاصیت Local است تا زمانیکه Context تعریف شده زنده نگه داشته شود. به همین جهت در برنامه جاری از روش زنده نگه داشتن Context به ازای یک ViewModel استفاده شده است.
به Context، توسط اینترفیس IUnitOfWork تزریق شده در سازنده کلاس ViewModel می‌توان دسترسی یافت. چون در اینجا از تزریق وابستگی‌ها استفاده شده است، وهله‌ای که IUnitOfWork کلاس AddNewUserViewModel را تشکیل می‌دهد، دقیقا همان وهله‌ای است که در کلاس UsersService لایه سرویس استفاده شده است. در نتیجه، در گرید برنامه هر تغییری اعمال شود، تحت نظر IUnitOfWork خواهد بود و صرفا با فراخوانی متد uow.ApplyAllChanges آن، کلیه تغییرات تمام ردیف‌های تحت نظر EF به صورت خودکار در بانک اطلاعاتی درج و یا به روز خواهند شد.
همچنین در مورد ViewModelContextHasChanges نیز در قسمت قبل بحث شد. در اینجا پیاده سازی کننده آن صرفا خاصیت uow.ContextHasChanges است. به این ترتیب اگر کاربر، تغییری را در صفحه داده باشد و بخواهد به صفحه دیگری رجوع کند، با پیام زیر مواجه خواهد شد:


از همین خاصیت برای فعال و غیرفعال کردن دکمه ذخیره سازی اطلاعات نیز استفاده شده است:
  /// <summary>
  /// فعال و غیرفعال سازی خودکار دکمه ثبت
  /// این متد به صورت خودکار توسط RelayCommand کنترل می‌شود
  /// </summary>  
  private bool canDoSave()
  {
     // آیا در حین نمایش صفحه‌ای دیگر باید به کاربر پیغام داد که اطلاعات ذخیره نشده‌ای وجود دارد؟
     return ViewModelContextHasChanges;
  }
این متد توسط RelayCommand ایی به نام  DoSave
  /// <summary>
  /// رخداد ذخیره سازی اطلاعات را دریافت می‌کند
  /// </summary>
  public RelayCommand DoSave { set; get; }
که به نحو زیر مقدار دهی شده است، مورد استفاده قرار می‌گیرد:
DoSave = new RelayCommand(doSave, canDoSave);
به ازای هر تغییری در UI، این RelayCommand به نتیجه canDoSave مراجعه کرده و اگر خروجی آن true باشد، دکمه متناظر را به صورت خودکار فعال می‌کند و یا برعکس.
این بررسی نیز بسیار سبک و سریع است. از این جهت که تغییرات Context در حافظه نگهداری می‌شوند و مراجعه به آن مساوی مراجعه به بانک اطلاعاتی نیست.
مطالب
بررسی تغییرات Blazor 8x - قسمت اول - معرفی SSR
از لحاظ تاریخی، Blazor به همراه دو حالت اصلی است:
- Blazor Server، که در آن یک اتصال SignalR، بین مرورگر کاربر و سرور، برقرار شده و سرور حالات مختلف این جلسه‌ی کاری را مدیریت می‌کند. آغاز این حالت، بسیار سریع است؛ اما وجود اتصال دائم SignalR در آن ضروری است. نیاز به وجود این اتصال دائم، با تعداد بالای کاربر می‌تواند کارآیی سرور را تحت تاثیر قرار دهد.
- Blazor WASM: در این حالت کل برنامه‌ی Blazor، درون مرورگر کاربر اجرا می‌شود و برای اینکار الزاما نیازی به سرور ندارد؛ اما آغاز اولیه‌ی آن به علت نیاز به بارگذاری کل برنامه درون مرورگر کاربر، اندکی کند است. اتصال این روش با سرور، از طریق روش‌های متداول کار با Web API صورت می‌گیرد و نیازی به اتصال دائم SignalR را ندارد.

دات نت 8، دو تغییر اساسی را در اینجا ارائه می‌دهد:
- در اینجا حالت جدیدی به نام SSR یا Static Server Rendering ارائه شده‌است (به آن Server-side rendering هم می‌گویند). در این حالت نه WASM ای درون مرورگر کاربر اجرا می‌شود و نه اتصال دائم SignalR ای برای کار با آن نیاز است! در این حالت برنامه تقریبا همانند یک MVC Razor application سنتی کار می‌کند؛ یعنی سرور، کار رندر نهایی HTML قابل ارائه‌ی به کاربر را انجام داده و آن‌را به سمت مرورگر، برای نمایش ارسال می‌کند و همچنین سرور، هیچ حالتی را هم از برنامه ذخیره نمی‌کند و به‌علاوه، کلاینت نیز نیازی به دریافت کل برنامه را در ابتدای کار ندارد (هم آغاز و نمایش سریعی را دارد و هم نیاز به منابع کمتری را در سمت سرور برای اجرا دارد).
- تغییر مهم دیگری که در دات نت 8 صورت گرفته، امکان ترکیب کردن حالت‌های مختلف رندر صفحات، در برنامه‌های Blazor است. یعنی می‌توان یک صفحه‌ی SSR را داشت که تنها قسمت کوچکی از آن بر اساس معماری Blazor Server کار کند (قسمت‌‌های اصطلاحا interactive یا تعاملی آن). یا حتی در یک برنامه، امکان ترکیب Blazor Server و Blazor WASM نیز وجود دارد.

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


تاریخچه‌ی نمایش صفحات وب در مرورگرها

در ابتدای ارائه‌ی وب، سرورها، ابتدا درخواستی را از طرف مرورگر کلاینت دریافت می‌کردند و در پاسخ به آن، HTML ای را تولید و بازگشت می‌دادند. حاصل آن، نمایش یک صفحه‌ی استاتیک non-interactive بود (غیرتعاملی). علت تاکید بر روی واژه‌ی interactive (تعاملی)، بکارگیری گسترده‌ی آن در نگارش جدید Blazor است؛ تا حدی که ایجاد قالب‌های جدید آغازین برنامه‌های آن، با تنظیم این گزینه همراه است. برای مشاهده‌ی آن، پس از نصب SDK جدید دات نت، دستور dotnet new blazor --help را صادر کنید.
سپس JavaScript از راه رسید و هدف آن، افزودن interactivity به صفحات سمت کاربر بود تا بتوان بر اساس تعاملات و ورودی‌های کاربر، تغییراتی را بر روی محتوای صفحه اعمال کرد. در ادامه JavaScript این امکان را یافت تا بتواند درخواست‌هایی را به سمت سرور ارسال کند و بر اساس خروجی دریافتی، قسمت‌هایی از صفحه‌ی جاری استاتیک را به صورت پویا تغییر دهد.
در ادامه با بالارفتن توانمندی‌های سخت‌افزاری و همچنین توسعه‌ی کتابخانه‌های جاوااسکریپتی، به برنامه‌های تک صفحه‌ای کاملا پویا و interactive رسیدیم که به آن‌ها SPA گفته می‌شود (Single-page applications)؛ از این دست کتابخانه‌ها می‌توان به Backbone اشاره کرد و پس از آن به React و Angular. برنامه‌های Blazor نیز اخیرا به این جمع اضافه شده‌اند.
اما ... اخیرا توسعه دهنده‌ها به این نتیجه رسیده‌اند که SPAها برای تمام امور، مناسب و یا حتی الزامی نیستند. گاهی از اوقات ما فقط نیاز داریم تا محتوایی را خیلی سریع و بهینه تولید و بازگشت دهیم؛ مانند نمایش لیست اخبار، به هزاران دنبال کننده، با حداقل مصرف منابع و در همین حال نیاز به interactivity در بعضی از قسمت‌های خاص نیز احساس می‌شود. این رویه‌ای است که در تعدادی از فریم‌ورک‌های جدید و مدرن جاوااسکریپتی مانند Astro در پیش گرفته شده‌است؛ در آن‌ها ترکیبی از رندر سمت سرور، به همراه interactivity سمت کاربر، مشاهده می‌شود. برای مثال این امکان را فراهم می‌کنند تا محتوای قسمتی از صفحه را در سمت سرور تهیه و رندر کنید، یا قسمتی از صفحه (یک کامپوننت خاص)، به صورت interactive فعال شود. ترکیب این دو مورد، دقیقا هدف اصلی Blazor، در دات نت 8 است. برای مثال فرض کنید می‌خواهید برنامه و سایتی را طراحی کنید که چند صفحه‌ی آغازین آن، بدون هیچگونه تعاملی با کاربر هستند و باید سریع و SEO friendly باشند. همچنین تعدادی از صفحات آن هم قرار است فقط یک سری محتوای ثابت را نمایش دهند، اما در قسمت‌های خاصی از آن نیاز به تعامل با کاربر است.


معرفی Blazor یکپارچه در دات نت 8

مهم‌ترین تغییر Blazor در دات نت 8، یکپارچه شدن حالت‌های مختلف رندر آن در سمت سرور است. تغییرات زیاد رخ داده‌اند تا امکان داشتن Server-side rendering یا SSR به همراه قابلیت فعال سازی interactivity به ازای هر کامپوننت دلخواه که به آن حالت‌های رندر (Render modes) گفته می‌شود، میسر شوند. در اساس، این روش جدید، همان Blazor Server بهبود یافته‌است که حالت SSR، حالت پیش‌فرض آن است. در کنار آن قابلیت‌های راهبری (navigation)، نیز بهبود یافته‌اند تا برنامه‌های SSR همانند برنامه‌های SPA به‌نظر برسند.

در دات نت 8، ASP.NET Core و Blazor نیز کاملا یکپارچه شده‌اند. در این حالت برنامه‌های Blazor Server می‌توانند همانند برنامه‌های MVC Razor Pages متداول، با کمک قابلیت SSR، صفحات غیر interactive ای را رندر کنند؛ البته به کمک کامپوننت‌های Razor. مزیت آن نسبت به  MVC Razor Pages این است که اکنون می‌توانید هر کامپوننت مجزایی از صفحه را نیز کاملا interactive کنید.
در نگارش‌های قبلی Blazor، برنامه‌های Blazor Server حتی برای شروع کار نیاز به یک صفحه‌ی Razor Pages آغازین داشتند، اما دیگر نیازی به این مورد با دات نت  8 نیست؛ چون ASP.NET Core 8x می‌تواند کامپوننت‌های Razor را نیز به صورت HTML خالص بازگشت دهد و یا Minimal API آن به همراه خروجی new RazorComponentResult نیز شده‌است. در حالت SSR، حتی سیستم مسیریابی ASP.NET Core نیز با Blazor یکی شده‌است.

البته این تغییرات، حالت‌های خالص Blazor WebAssembly و یا MAUI Blazor Hybrid را تحت تاثیر قرار نمی‌دهند؛ اما بدیهی است تمام آن‌ها از سایر قابلیت‌های جدید اضافه شده نیز بهره‌مند هستند.


معرفی حالت‌های مختلف رندر Blazor در دات نت 8

یک برنامه‌ی جدید 8x Blazor، در اساس بر روی سرور رندر می‌شود (همان SSR). اما همانطور که عنوان شد، این SSR ارائه شده‌ی توسط Blazor، یک قابلیت مهم را نسبت به MVC Razor pages دارد و آن هم امکان فعالسازی interactivity، به ازای کامپوننت‌ها و قسمت‌های کوچکی از صفحه است که واقعا نیاز است تعاملی باشند. فعالسازی آن هم بسیار ساده، یک‌دست و یکپارچه است:
@* For being rendered on the server *@
<Counter @rendermode="@InteractiveServer" />

@* For running in WebAssembly *@
<Counter @rendermode="@InteractiveWebAssembly" />
در این حالت می‌توان مشخص کرد که آیا قرار است این کامپوننت خاصی که در قسمتی از صفحه‌ی جاری قرار است رندر شود، نیاز است به کمک فناوری وب‌اسمبلی اجرا شود و یا قرار است بر روی سرور رندر شود؟

این تعاریف حالت رندر را توسط دایرکتیوها نیز می‌توان به ازای هر کامپوننت مجزا، مشخص کرد (یکی از این دو حالت باید بکار گرفته شود):
@rendermode InteractiveServer

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


معرفی حالت رندر خودکار در Blazor 8x

یکی دیگر از حالت‌های رندر معرفی شده‌ی در Blazor 8x، حالت Auto است:
<Counter @rendermode="@InteractiveAuto" />
این حالت رندر، به صورت پیش‌فرض از WebAssembly استفاده می‌کند؛ اما فقط زمانیکه فایل‌های مرتبط با آن کاملا دریافت شده‌باشند. یعنی در ابتدای کار برای ارائه‌ی امکانات تعاملی، از حالت سریع و سبک InteractiveServer استفاده می‌کند؛ اما در پشت صحنه مشغول به دریافت فایل‌های مرتبط با نگارش وب‌اسمبلی کامپوننت فوق خواهد شد. پس از بارگذاری و کش شدن این فایل‌ها، برای بارهای بعدی رندر، فقط از حالت وب‌اسمبلی استفاده می‌کند.


معرفی حالت رندر Streaming در Blazor 8x

در بار اول بارگذاری صفحات، ممکن است دریافت اطلاعات مرتبط با آن کمی کند و با وقفه باشند. در این حالت برای اینکه برنامه‌های SSR یک صفحه‌ی خالی را نمایش ندهند، می‌توان در ابتدا با استفاده از حالت رندر جدید StreamRendering، حداقل قالب صفحه را نمایش داد و سپس اصل اطلاعات را:
@attribute [StreamRendering(prerender: true)]
این روش، از HTTP Streaming در پشت صحنه استفاده کرده و مرحله به مرحله قسمت‌های تکمیل شده را به سمت مرورگر کاربر، برای نمایش نهایی ارسال می‌کند.


جزئیات بیشتر نحوه‌ی کار با این حالات را در قسمت‌های بعدی بررسی خواهیم کرد.


نتیجه گیری:

روش‌های جدید رندر ارائه شده‌ی در Blazor 8x، برای موارد زیر مفید هستند:
- زمانیکه قسمت عمده‌ای از برنامه‌ی شما بر روی سرور اجرا می‌شود.
- زمانیکه خروجی اصلی برنامه‌ی شما بیشتر حاوی محتواهای ثابت است؛ مانند CMSها.
- زمانیکه می‌خواهید صفحات شما قابل ایندکس شدن توسط موتورهای جستجو باشند و مباحث SEO برای شما مهم است.
- زمانیکه نیاز به مقدار کمی امکانات تعاملی دارید و فقط قسمت‌های کوچکی از صفحه قرار است تعاملی باشند. برای مثال فقط قرار است قسمت کوچکی از یک صفحه‌ی نمایش مقاله‌ای از یک بلاگ، به همراه امکان رای دادن به آن مطلب (تنها قسمت «تعاملی» صفحه) باشد.
- و یا زمانیکه می‌خواهید MVC Razor Pages را با یک فناوری جدید که امکانات بیشتری را در اختیار شما قرار می‌دهد، جایگزین کنید.