نظرات مطالب
ASP.NET MVC #7
برای توضیحات بیشتر در مورد Model و model به قسمت پنجم مراجعه کنید.
توضیح تکمیلی:
- کلاس پایه‌ای در ASP.NET MVC وجود دارد به نام  (^)WebViewPage. این کلاس حاوی تعاریف اولیه TempData، ViewBag، ViewData و ... Model است. این Model ریشه‌اش به اینجا بر می‌گردد و با حرف بزرگ شروع شده است. بنابراین در Viewهای سی شارپ Razor برای تعریف نوع مدل نیاز است بین model و شیء Model تفاوت وجود داشته باشد.
- در یک View شما هر تعداد مدل رو می‌تونید از طریق ViewBag و ViewData و غیره که در قسمت 5 توضیح داده شده، دریافت کنید و محدودیتی ندارد. اما این‌ها هیچکدام به معنای Strongly typed بودن View نیست. بنابراین برای حالت داشتن View از نوع Strongly typed، یکبار باید این نوع، تعریف شود.
البته یک راه هوشمندانه برای ارسال بیش از یک شیء به Model وجود دارد. یک کلاس تعریف کنید که خواص آن چندین شیء مورد نظر شما باشند. سپس این کلاس را به عنوان نوع Model در ابتدای View معرفی کنید. در اینجا به راحتی و به صورت Strongly typed با چند شیء می‌شود به عنوان Model کار کرد.
نظرات مطالب
خلاصه‌ای کوتاه در مورد WinRT
خیر. به WinRT یا Windows run time جدید به چشم Silverlight run time نگاه کنید. لایه‌ای است بالاتر از Win32 API که برفراز آن‌ می‌شود برنامه توسعه داد (WPF فقط یک روش طراحی رابط کاربری جدید است، run time نیست). WinRT شبیه به همان مدل امنیتی بسته سیلورلایت را به ارث برده. همان لایه نمایش XAML را به ارث برده. با این تفاوت که این run time جدید آن علاوه بر XAML ، امکان کار با HTML5 و جاوا اسکریپت را هم می‌دهد و محدود به XAML نیست. برخلاف سیلورلایت، این run time فقط محدود به دات نت هم نیست و با CPP و Native کد هم می‌شود با آن کار کرد. به این نتیجه رسیدند که طراحی خوبی انجام دادن، خوب چرا فقط دات نت استفاده کند؟
ضمنا این محدودیت‌های امنیتی ذکر شده برای آن قطعا برای خیلی از برنامه نویس‌ها خوشایند نخواهد بود. برای دسترسی بیشتر، مجبور خواهند شد به سیستم‌های دسکتاپ سابق رجوع کنند.
نظرات مطالب
یکسان سازی ی و ک دریافتی حین استفاده از NHibernate
این مشکلات زمان VB6 (مرحوم) هم بود (مثلا هنگام انتخاب فونت برای یک متن فارسی باید script آن را در صفحه انتخاب فونت روی Arabic گذاشت تا درست نمایش داده شود). قبل از دات نت. قبل از یونیکد شدن رشته‌ها در سیستم‌های متداول دات نت به صورت پیش فرض از نگارش یک آن.
دلفی‌های جدید هم به نظر رشته یونیکد را پیش فرض خود کرده‌اند (نگارش‌های بعد از 2007). بهتر است برنامه خودتون رو به این نگارش‌ها ارتقاء بدید (تا به صورت خودکار همه چیز منجمله کامپوننت‌ها(ی جدید) بر مبنای رشته‌های یونیکد کار کنند)، همچنین بانک اطلاعاتی هم باید واقعا رشته‌های یونیکد را ساپورت کند. مثلا در SQL Server ، بین نوع‌های varchar و nvarchar تفاوت وجود دارد.
در کل من با این صفحه کلید و برنامه‌های دات نت، نه مشکلی در ثبت دارم و نه مشکلی در نمایش (چند سال هست). همچنین نیم فاصله هم جهت تایپ فارسی پشتیبانی می‌شود + ساپورت فونت‌های قدیمی هم لحاظ شده.
مطالب
تنظیمات مدت زمان اعتبار کاربران در ASP.NET Identity
نکته: در این مقاله کلمه "بازه زمانی" معادل Interval می‌باشد.
اگر از سیستم احراز هویت از طریق کوکی در asp.net Identity 2.1 استفاده می‌کنید، دو تنظیم برای  بررسی پایان یافتن اعتبار کاربر وجود دارد که در نگاه اول، هیچ تفاوتی باهم نداشته و شبیه به هم به نظر می‌رسند: ValidateInterval و ExpireTimeSpan
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
        OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
            validateInterval: TimeSpan.FromMinutes(15),
            regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)),
    },
    SlidingExpiration = false,
    ExpireTimeSpan = TimeSpan.FromMinutes(30)
});

ExpireTimeSpan

CookieAuthenticationOptions.ExpireTimeSpan یک خصیصه است که به شما اجازه می‌دهد تا مدت زمان اعتبار کوکی ساخته شده توسط Identity را مشخص کنید. در مثال بالا، کوکی به مدت 30 دقیقه از زمان ایجاد آن، معتبر است. هنگامی که این 30 دقیقه به پایان برسد، کاربر باید مجددا لاگین کند، چون SlidingExpiration به false تنظیم شده است.
اگر SlidingExpiration مقدار true داشته باشد، کوکی بعد از هر درخواستی که پس از گذشت بیش از نیمی از مدت زمان مشخص شده در ExpireTimeSpan ارسال شود، مجددا ایجاد خواهد شد. برای مثال در اینجا (با توجه قطعه به کد بالا) اگر کاربر login شود و درخواست بعدی را پس از گذشت 16 دقیقه ارسال کند، کوکی به مدت 30 دقیقه دیگر معتبر خواهد شد. اما اگر کاربر پس از لاگین، در خواست بعدی را 31 دقیقه بعد ارسال کند، باید مجددا عمل لاگین را انجام دهد.

بازه زمانی اعتبارسنجی SecurityStampValidator

ValidateInterval از تابع SecurityStampValidator.OnValidateIdentity، فیلد SecurityStamp را بعد از گذشت یک بازه زمانی بررسی می‌کند تا از اعتبار کوکی اطمینان حاصل شود. این همان بررسی منقضی شدن کوکی نیست، اگرچه می‌تواند سبب همان عملکرد و یا لاگ آوت کاربر شود.
Security Stamp هربار که رمز عبور ایجاد یا عوض شود و یا یک لاگین خارجی (External Login) ایجاد یا حذف شود، به روز می‌شود. اگر کاربر رمز عبورش را تغییر دهد این فیلد تغییر خواهد کرد و این تغییر باعث می‌شود که در بررسی مجدد این فیلد پس از مدت زمان مشخص شده در ValidateInterval، کوکی نامعتبر شناخته شود و کاربر را مجبور به لاگین مجدد کند.
نکته: در صورتی که بخواهید به صورت دستی مقدار این فیلد را تغییر دهید می‌توانید از کد زیر استفاده کنید:
UserManager.UpdateSecurityStampAsync(userId);
برای درک بهتر مثال زیر را در نظر بگیرید:
  1. کاربر در مکان A لاگین می‌شود.
  2. همان کاربر مکان خود را تغییر داده و ده دقیقه بعد در مکان B لاگین می‌شود.
  3. کاربر رمزعبورش را در مکان B در دقیقه 12ام تغییر می‌دهد.
  4. کاربر به مکان A برمی گردد و یک درخواست را در دقیقه 20ام ارسال می‌کند.
  5. چون کاربر یک درخواست را بعد از مدت زمان مشخص شده در ValidateInterval (یعنی 15 دقیقه) در مکان A ارسال می‌کند، پس عملیات چک کردن فیلد SecurityStamp انجام می‌شود و از آنجایی که این فیلد به علت تغییر رمز عبور، به روز شده است، بنابراین کاربر لاگ آوت خواهد شد.
دلیل لاگ آوت شدن کاربر در این سناریو، با حالتی که کوکی منقضی می‌شود تفاوت دارد، چون مدت زمان انقضای کوکی یعنی 30 دقیقه (در این مثال) هرگز نمی‌رسد. درعین حال کاربر لاگ آوت می‌شود چون مقدار validateInterval بر روی 15 دقیقه تنظیم شده است.

تفاوت این دو چیست؟
تفاوت دو حالت در نگاه اول خیلی ظریف است اما این تفاوت مزایای بزرگی فراهم می‌کند، مانند لاگ آوت کردن از هر مکان. اما این ویژگی می‌تواند گیج کننده هم باشد از آنجا که الگوی پیش فرض ASP.NET Identity فقط validateInterval را دارد و ExpireTimeSpan به طور صریح ذکر نشده و مقدار پیش فرض آن روی 14 روز تنظیم شده است.
مطالب
آشنایی با BOM !

سؤال: دو فایل زیرنویس فارسی داریم، هر دو هم با فرمت UTF-8 ذخیره شده‌اند. یکی در دستگاه DVD Player درست نمایش داده می‌شود و دیگری خیر. چرا؟!
هر دو فایل را اگر در یک ادیتور متنی باز کنیم تفاوتی قابل مشاهده نیست؛ اما در یک Hex Editor خیر:



در سه بایت اول فایل با هم تفاوت دارند و اصطلاحا به این سه بایت BOM یا Byte order mark گفته می‌شود. توسط آن می‌توان تشخیص داد که فایل جاری اولا آیا با فرمت یونیکد ذخیره شده است یا خیر ثانیا کدام حالت به کار گرفته شده است؛ آیا UTF-8 است یا UTF-16 یا ...؟
در حالت UTF-8 مقدار BOM مساوی با 0xEF,0xBB,0xBF بوده و البته ذکر آن اختیاری است. به نظر این دستگاه DVD Player یاد شده، به این نکته حساس است.
در دات نت جهت اطمینان از نوشته شدن BOM در فایل تولیدی، نیاز است encoding نهایی صریحا ذکر گردد. برای مثال هرچند خروجی File.WriteAllText حتی بدون ذکر encoding آن، UTF-8 است، اما BOM را به همراه ندارد (^). برای رفع این مساله باید از روش زیر استفاده کرد:

File.WriteAllText(path, data, Encoding.UTF8);  


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

نظرات مطالب
مفاهیم برنامه نویسی ـ آشنایی با سازنده‌ها
ضمن تشکر از دوستانی که در بحث شرکت کردند و پوزش به دلیل اینکه چند هفته ای در سفر هستم و تهیه مطالب با تأخیر انجام خواهد شد.
برای پاسخ به پرسش دوست گرامی آقای نجف زاده ابتدا بخشی از این مطلب را یادآوری می‌کنم.
"... مساحت را این بار به جای متد به صورت یک پروپرتی پیاده سازی می‌کنیم. اگرچه در آینده بیشتر راجع به چگونگی انتخاب برای پیاده سازی یک عضو کلاس به صورت پروپرتی یا متد بحث خواهیم کرد اما به عنوان یک قانون کلی در نظر داشته باشید عضوی که به صورت منطقی به عنوان داده مطرح است را به صورت پروپرتی پیاده سازی کنید. مانند نام دانشجو. از طرفی اعضایی که دلالت بر انجام عملی دارند را به صورت متد پیاده سازی می‌کنیم. مانند متد تبدیل به نوع داده دیگر. (مثلاً ()Object.ToString) ..."

بنابراین به نکات زیر توجه فرمایید.
۱. در این مطالب سعی شده است امکان پیاده سازی یک مفهوم به دو صورت متد و پروپرتی نشان داده شود تا در ذهن خواننده زمینه ای برای بررسی بیشتر مفهوم متد و پروپرتی و تفاوت آن‌ها فراهم گردد. این زمینه برای کنجکاوی بیشتر معمولاً با انجام یک جستجوی ساده سبب توسعه و تثبیت علم شخص می‌گردد.
۲. در متن بالاً به صورت کلی اشاره شده است هر یک از دو مفهوم متد و پروپرتی در کجا باید استفاده شوند و نیز خاطرنشان شده است در مطالب بعدی در مورد این موضوع بیشتر صحبت خواهد شد.
۳. نکته مهم در طراحی کلاس، پایگاه داده و ... خرد جهان واقع یا محیط عملیاتی مورد نظر طراح است. به عبارت دیگر گسی نمی‌تواند به یک طراح بگوید به طور مثال مساحت باید متد باشد یا باید پروپرتی باشد. طراح با توجه به مفهوم و کارکردی که برای هر مورد در ذهن دارد بر اساس اصول و قواعد، متد یا پروپرتی را بر می‌گزیند. مثلاً در خرد جهان واقع موجود در ذهن یک طراح مساحت به عنوان یک عمل یا اکشنی که شیء انجام می‌دهد است و بنابراین متد را انتخاب می‌کند. طراح دیگری در خرد جهان واقع دیگری در حال طراحی است و مثلاً متراژ یک شیء خانه را به عنوان یک ویژگی ذاتی و داده ای می‌نگرد و گمان می‌کند خانه نیازی به انجام عملی برای بدست آوردن مساحت خود ندارد بلکه یکی از ویژگی‌های خود را می‌تواند به اطلاع استفاده کننده برساند. پس شما به طراح دیگر نگویید اکشن تلقی میشه پس باید متد استفاده شود. اگر خود در پروژه ای چیزی را اکشن تلقی نمودید بله باید متد به کار ببرید. تلقی‌ها بر اساس خرد جهان واقع معنا دارند.
۴. پروپرتی و متد از نظر شیوه استفاده و ... با هم تفاوت دارند. اما یک تفاوت مهم بین آنها بیان نوع مفاهیم موجود در ذهن طراح به کد مشتری است. فراموش نکنید خود پروپرتی دارای اکسسور است که چیزی مانند متد است. در خیلی از موارد صحیح‌تر بودن پیاده سازی با متد یا با پروپرتی معنا ندارد. انتخاب ما بین متد یا پروپرتی بر اساس نحوه استفاده مطلوب در کد مشتری و نیز اطلاع به مشتری که مثلاً فلان مفهوم از دید ما یک اکشن است و فلان چیز داده صورت می‌گیرد.

مطالب
یکی کردن اسمبلی‌ها با استفاده از Eazfuscator

نسخه جدید برنامه Eazfuscator به همراه دو قابلیت جالب یکی کردن و همچنین مدفون نمودن اسمبلی‌ها ارائه شده است:

یکی کردن چند اسمبلی با هم
Eazfuscator برای یکی کردن اسمبلی‌ها از برنامه معروف ILmerge استفاده می‌کند با این تفاوت که دیگر نیازی نیست تا پارامترهای آن‌را تنظیم کرد و بسیاری از مسایل را به صورت خودکار مدیریت می‌کند.
جهت فعال کردن این قابلیت، یکی از روش‌های کار به صورت زیر است:
فایلی به نام ObfuscationSettings.cs را به پروژه خود اضافه کرده، سپس محتویات آن‌را حذف نموده و با چند سطر زیر جایگزین و کامپایل کنید:
using System;
using System.Reflection;

[assembly: Obfuscation(Feature = "merge with file1.dll", Exclude = false)]
[assembly: Obfuscation(Feature = "merge with file2.dll", Exclude = false)]
[assembly: Obfuscation(Feature = "merge with file3.dll", Exclude = false)]

همانطور که ملاحظه می‌کنید این چند سطر حاوی نام اسمبلی‌هایی می‌باشند که قرار است با اسمبلی جاری یکی شوند.
سپس اسمبلی جاری را (می‌خواهد فایل exe باشد یا یک dll ، فرقی نمی‌کند) بر روی Eazfuscator کشیده و رها کنید. پس از چند لحظه اسمبلی نهایی تولید شده شامل تمام کلاس‌ها و منابع اسمبلی‌هایی خواهد بود که در فایل ObfuscationSettings.cs ذکر شده‌اند؛ به همراه Obfuscation خودکار آن‌ها.

مدفون کردن اسمبلی‌ها در یک اسمبلی
قابلیت دیگر این برنامه دفن (embedding) چند اسمبلی در اسمبلی نهایی است. برای فعال سازی آن روش کار همانند قبل است با این تفاوت که بجای merge with باید نوشت embed . برای مثال:
[assembly: Obfuscation(Feature = "embed Common.dll", Exclude = false)]

به این ترتیب اسمبلی‌های ذکر شده پس از رمزنگاری و فشرده شدن به صورت منابع اسمبلی جاری ذخیره خواهند شد. مدیریت استفاده از آن‌ها هم خودکار است و نیازی نیست تا کاری در این مورد صورت گیرد.
برای نمونه برنامه معروف LINQPad از همین روش استفاده می‌کند و لازم به ذکر است که ... هنوز که هنوز است هیچ ک.ر.ک. کارسازی برای فعال سازی قسمت intellisense آن که رایگان نیست ارائه نشده و تمام وصله‌های جدید ارائه شده کار نمی‌کنند ...

تفاوت مدفون کردن با یکی کردن چیست؟
در حالت یکی کردن اسمبلی‌ها، سربار اولیه بارگذاری برنامه همانند روش مدفون سازی وجود ندارد. اما این سربار آنقدر ناچیز است که کسی آن‌را احساس نخواهد کرد. مورد دیگر، عدم پشتیبانی از روش مدفون سازی در سایر سکوهای کاری مانند ویندوز فون، Compact Framework و غیره است. اما باید درنظر داشت که برای مثال ILMerge روی اسمبلی‌های دارای XAML کار نمی‌کند (مطابق مستندات رسمی آن). بنابراین همیشه نمی‌توان از روش یکی سازی استفاده کرد و محدودیت‌های خاص خودش را دارد.
در کل روش مدفون سازی به دلیل Obfuscation ، فشرده سازی و رمزنگاری همزمان، امنیت بیشتری را نسبت به حالت Obfuscation تنها ارائه می‌دهد (حداقل شخص "علاقمند" به مطالعه این نوع اسمبلی‌ها باید از چند لایه رد شود و تجربه برنامه LINQPad ثابت کرده که این روش در مقیاس کلان (در انظار عمومی هزاران علاقمند) بسیار موفق بوده است).

مطالب
بررسی تغییرات Blazor 8x - قسمت دوم - بررسی حالت رندر سمت سرور
در قسمت قبل، حالت‌های مختلف رندر کامپوننت‌ها را در Blazor 8x معرفی کردیم. در این قسمت می‌خواهیم نحوه‌ی کارکرد دو حالت InteractiveServer و StreamRendering را به همراه چند مثال بررسی کنیم.


معرفی قالب‌های جدید شروع پروژه‌های Blazor در دات نت 8

پس از نصب SDK دات نت 8، دیگر خبری از قالب‌های قدیمی پروژه‌های blazor server و blazor wasm نیست! در اینجا در ابتدا باید مشخص کرد که سطح تعاملی برنامه در چه حدی است. در ادامه 4 روش شروع پروژه‌های Blazor 8x را مشاهده می‌کنید که توسط پرچم interactivity--، نوع رندر برنامه در آن‌ها مشخص شده‌است:

اجرای قسمت‌های تعاملی برنامه بر روی سرور:
dotnet new blazor --interactivity Server

اجرای قسمت‌های تعاملی برنامه در مرورگر، توسط فناوری وب‌اسمبلی:
dotnet new blazor --interactivity WebAssembly

برای اجرای قسمت‌های تعاملی برنامه، ابتدا حالت Server فعالسازی می‌شود تا فایل‌های WebAssembly دریافت شوند، سپس فقط از WebAssembly استفاده می‌کند:
dotnet new blazor --interactivity Auto

فقط از حالت SSR یا همان static server rendering استفاده می‌شود (این نوع برنامه‌ها تعاملی نیستند):
dotnet new blazor --interactivity None

سایر گزینه‌ها را با اجرای دستور dotnet new blazor --help می‌توانید مشاهده کنید.


نکته‌ی مهم! در قالب‌های آماده‌ی Blazor 8x، حالت SSR، پیش‌فرض است.

هرچند در تمام پروژه‌های فوق، انتخاب حالت‌های مختلف رندر را مشاهده می‌کنید، اما این انتخاب‌ها صرفا دو مقصود مهم را دنبال می‌کنند:
الف) تنظیم فایل Program.cs برنامه جهت افزودن وابستگی‌های مورد نیاز، به صورت خودکار.
ب) ایجاد پروژه‌ی کلاینت (علاوه بر پروژه‌ی سرور)، در صورت نیاز. برای مثال حالت‌های وب‌اسمبلی و Auto، هر دو به همراه یک پروژه‌ی کلاینت وب‌اسمبلی هم هستند؛ اما حالت‌های Server و None، خیر.

در تمام این پروژه‌ها هر صفحه و یا کامپوننتی که ایجاد می‌شود، به صورت پیش‌فرض بر اساس SSR رندر و نمایش داده خواهد شد؛ مگر اینکه به صورت صریحی این نحوه‌ی رندر را بازنویسی کنیم. برای مثال مشخص کنیم که قرار است بر اساس Blazor Server اجرا شود و یا وب‌اسمبلی و یا حالت Auto.

اما ... اگر علاقمند بودیم تا به حالت‌های پیش‌از دات نت 8 رجوع کنیم و تمام برنامه را به صورت یک‌دست تعاملی کنیم و حالت SSR پیش‌فرض نباشد، می‌توان از پرچم all-interactive-- که به انتهای دستورات فوق قابل افزوده شدن است، کمک گرفت. این پرچم، فایل App.Razor را جهت تنظیم سراسری حالت‌های رندر، ویرایش می‌کند. این مورد را در ادامه‌ی این مطلب، در قسمت «روشی ساده برای تعاملی کردن کل برنامه» بیشتر بررسی می‌کنیم.


بررسی حالت Server side rendering

برای بررسی این حالت یک پوشه‌ی جدید را ایجاد کرده و توسط خط فرمان، دستور dotnet new blazor --interactivity Server را در ریشه‌ی آن اجرا می‌کنیم. پس از ایجاد ساختار ابتدایی پروژه بر اساس این قالب انتخابی، فایل Program.cs جدید آن، چنین شکلی را دارد:
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddRazorComponents().AddInteractiveServerComponents();

var app = builder.Build();

if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error", createScopeForErrors: true);
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();
app.UseAntiforgery();

app.MapRazorComponents<App>().AddInteractiveServerRenderMode();

app.Run();
مهم‌ترین قسمت‌های آن، متدهای AddInteractiveServerComponents و AddInteractiveServerRenderMode هستند که server-side rendering را به همراه امکان داشتن کامپوننت‌های تعاملی، میسر می‌کنند.
server-side rendering به این معنا است که برنامه‌ی سمت سرور، کل DOM و HTML نهایی را تولید کرده و به مرورگر کاربر ارائه می‌کند. مرورگر هم این DOM را نمایش می‌دهد. فقط همین! در اینجا هیچ خبری از اتصال دائم SignalR نیست و محتوای ارائه شده، یک محتوای استاتیک است. این حالت رندر، برای ارائه‌ی محتواهای فقط خواندنی غیرتعاملی، فوق العاده‌است؛ امکان از لحظه‌ای که نیاز به کلیک بر روی دکمه‌ای باشد، دیگر پاسخگو نیست. به همین جهت در اینجا امکان تعاملی کردن تعدادی از کامپوننت‌های ویژه و مدنظر نیز پیش‌بینی شده‌اند تا بتوان به ترکیبی از server-side rendering و client-side rendering رسید.
حالت پیش‌فرض در اینجا، ارائه‌ی محتوای استاتیک است. بنابراین هر کامپوننتی در اینجا ابتدا بر روی سرور رندر شده (HTML ابتدایی آن آماده شده) و به سمت مرورگر کاربر ارسال می‌شود. اگر کامپوننتی نیاز به امکانات تعاملی داشت باید آن‌را دقیقا توسط ویژگی InteractiveXYZ مشخص کند؛ مانند مثال زیر:
@page "/counter"
@rendermode InteractiveServer

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
    }
}
همانطور که مشاهده می‌کنید، این کامپوننت از روش رندر InteractiveServer استفاده می‌کند. برای درک نحوه‌ی کارکرد آن، همین سطر را حذف، یا کامنت کنید و سپس برنامه را اجرا کنید. در حین مشاهده‌ی این صفحه، همه چیز به خوبی نمایش داده می‌شود و حتی دکمه‌ی Click me هم مشخص است. اما ... با کلیک بر روی آن اتفاقی رخ نمی‌دهد! علت اینجا است که اکنون این صفحه، یک صفحه‌ی کاملا استاتیک است و دیگر تعاملی نیست.
در ادامه، مجددا سطر کامنت شده را به حالت عادی برگردانید و سپس برنامه را اجرا کنید. پیش از باز کردن صفحه‌ی Counter، ابتدا developer tools مرورگر خود را گشوده و برگه‌ی network آن‌را انتخاب و سپس صفحه‌ی Counter را باز کنید. در این لحظه‌است که مشاهده می‌کنید یک اتصال وب‌سوکت برقرار شد. این اتصال است که قابلیت‌های تعاملی صفحه را برقرار کرده و مدیریت می‌کند (این اتصال دائم SignalR است که این صفحه را همانند برنامه‌های Blazor Web Server پیشین مدیریت می‌کند).

یک نکته: در برنامه‌های Blazor Server سنتی، امکان فعالسازی قابلیتی به نام prerender نیز وجود دارد. یعنی سرور، ابتدا صفحه را رندر کرده و محتوای استاتیک آن‌را به سمت مرورگر کاربر ارسال می‌کند و سپس اتصال SignalR برقرار می‌شود. در دات نت 8، این حالت، حالت پیش‌فرض است. اگر آن‌را نمی‌خواهید باید به نحو زیر غیرفعالش کنید:
@rendermode InteractiveServerRenderModeWithoutPrerendering

@code{
  static readonly IComponentRenderMode InteractiveServerRenderModeWithoutPrerendering = 
        new InteractiveServerRenderMode(false);
}


روشی ساده برای تعاملی کردن کل برنامه

اگر می‌خواهید رفتار برنامه را همانند Blazor Server سابق کنید و نمی‌خواهید به ازای هر کامپوننت، نحوه‌ی رندر آن‌را به صورت سفارشی انتخاب کنید، فقط کافی است فایل App.razor را باز کرده:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <base href="/" />
    <link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
    <link rel="stylesheet" href="app.css" />
    <link rel="stylesheet" href="MyApp.styles.css" />
    <link rel="icon" type="image/png" href="favicon.png" />
    <HeadOutlet />
</head>

<body>
    <Routes />
    <script src="_framework/blazor.web.js"></script>
</body>

</html>
و قسمت‌های HeadOutlet و مسیریابی آن‌را به صورت زیر تغییر دهید تا به کل برنامه اعمال شود:
<HeadOutlet @rendermode="@InteractiveServer" />
...
<Routes @rendermode="@InteractiveServer" />
این مورد دقیقا همان کاری است که پرچم all-interactive-- در هنگام ایجاد پروژه‌های جدید Blazor 8x به کمک NET CLI.، انجام می‌دهد. یک چنین گزینه‌ای در ویژوال استودیو نیز هنگام ایجاد پروژه‌ها‌ی جدید Blazor وجود دارد و به شما این امکان را می‌دهد که بین حالت‌های تعاملی Per page/component و Global، یکی را انتخاب کنید. در حین استفاده‌ی از CLI، نیازی به ذکر حالت تعاملی Per page/component نیست؛ چون حالت پیش‌فرض، یا همان SSR است. حالت Global هم فقط فایل App.Razor را به صورت فوق، ویرایش و تنظیم می‌کند.


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


بررسی حالت Streaming Rendering

در اینجا مثال پیش‌فرض Weather.razor قالب پیش‌فرض مورد استفاده‌ی جاری را کمی تغییر داده‌ایم که کدهای نهایی آن به صورت زیر است (2 قسمت forecasts.AddRange_ را اضافه‌تر دارد):

@page "/weather"
@attribute [StreamRendering(prerender: true)]

<PageTitle>Weather</PageTitle>

<h1>Weather</h1>

<p>This component demonstrates showing data.</p>

@if (_forecasts == null)
{
    <p>
        <em>Loading...</em>
    </p>
}
else
{
    <table class="table">
        <thead>
        <tr>
            <th>Date</th>
            <th>Temp. (C)</th>
            <th>Temp. (F)</th>
            <th>Summary</th>
        </tr>
        </thead>
        <tbody>
        @foreach (var forecast in _forecasts)
        {
            <tr>
                <td>@forecast.Date.ToShortDateString()</td>
                <td>@forecast.TemperatureC</td>
                <td>@forecast.TemperatureF</td>
                <td>@forecast.Summary</td>
            </tr>
        }
        </tbody>
    </table>
}

@code {
    private List<WeatherForecast>? _forecasts;

    protected override async Task OnInitializedAsync()
    {
    // Simulate asynchronous loading to demonstrate streaming rendering
        await Task.Delay(500);

        var startDate = DateOnly.FromDateTime(DateTime.Now);
        var summaries = new[]
                        {
                            "Freezing",
                            "Bracing",
                            "Chilly",
                            "Cool",
                            "Mild",
                            "Warm",
                            "Balmy",
                            "Hot",
                            "Sweltering",
                            "Scorching",
                        };
        _forecasts = GetWeatherForecasts(startDate, summaries).ToList();
        StateHasChanged();

    // Simulate asynchronous loading to demonstrate streaming rendering
        await Task.Delay(1000);
        _forecasts.AddRange(GetWeatherForecasts(startDate, summaries));
        StateHasChanged();

        await Task.Delay(1000);
        _forecasts.AddRange(GetWeatherForecasts(startDate, summaries));
    }

    private static IEnumerable<WeatherForecast> GetWeatherForecasts(DateOnly startDate, string[] summaries)
    {
        return Enumerable.Range(1, 5)
                         .Select(index => new WeatherForecast
                                          {
                                              Date = startDate.AddDays(index),
                                              TemperatureC = Random.Shared.Next(-20, 55),
                                              Summary = summaries[Random.Shared.Next(summaries.Length)],
                                          });
    }

    private class WeatherForecast
    {
        public DateOnly Date { get; set; }
        public int TemperatureC { get; set; }
        public string? Summary { get; set; }
        public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    }

}
برای بررسی این مثال، ابتدا سطر ویژگی StreamRendering را حذف و یا کامنت کرده و سپس برنامه را اجرا کنید. پس از اجرای برنامه، با انتخاب مشاهده‌ی صفحه‌ی Weather، هیچگاه قسمت loading که در حالت forecasts == null_ قرار است ظاهر شود، نمایش داده نمی‌شود؛ چون در این حالت (حذف نوع رندر)، صفحه‌ی نهایی که به کاربر ارائه خواهد شد، یک صفحه‌ی استاتیک کاملا رندر شده‌ی در سمت سرور است و کاربر باید تا زمان پایان این رندر در سمت سرور، منتظر بماند و سپس صفحه‌ی نهایی را دریافت و مشاهده کند. در این حالت امکانات تعاملی Blazor server وجود خارجی ندارند.
در ادامه مجددا سطر ویژگی StreamRendering را به حالت قبلی برگردانید و برنامه را اجرا کنید. در این حالت ابتدا قسمت loading ظاهر می‌شود و سپس در طی چند مرحله با توجه به Task.Delay‌های قرار داده شده، صفحه رندر شده و تکمیل می‌شود.
اتفاقی که در اینجا رخ می‌دهد، استفاده از فناوری  HTML Streaming است که مختص به مایکروسافت هم نیست. در حالت Streaming، هربار قطعه‌ای از HTML ای که قرار است به کاربر ارائه شود، به صورت جریانی به سمت مرورگر ارسال می‌شود و مرورگر این قطعه‌ی جدید را بلافاصله نمایش می‌دهد. نکته‌ی جالب این روش، عدم نیاز به اتصال SignalR و یا اجرای WASM درون مرورگر است.

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


روش نهایی معرفی نحوه‌ی رندر صفحات

بجای استفاده از ویژگی‌های RenderModeXyz جهت معرفی نحوه‌ی رندر کامپوننت‌ها و صفحات (که تا پیش از نگارش RTM معرفی شده بودند و چندبار هم تغییر کردند)، می‌توان از دایرکتیو جدیدی به نام rendermode@ با سه مقدار InteractiveServer، InteractiveWebAssembly و InteractiveAuto استفاده کرد. برای سهولت تعریف این موارد باید سطر ذیل را به فایل Imports.razor_ اضافه نمود:
@using static Microsoft.AspNetCore.Components.Web.RenderMode
در این حالت تعریف قدیمی سطر ذیل:
@attribute [RenderModeInteractiveServer]
به صورت زیر:
@rendermode InteractiveServer
تبدیل می‌شود.

اگر هم قصد سفارشی سازی آن‌ها را دارید، برای مثال می‌خواهید prerender را در آن‌ها false کنید، روش کار به صورت زیر است:
@rendermode renderMode

@code {
    static IComponentRenderMode renderMode = new InteractiveWebAssemblyRenderMode(prerender: false);
}