اندازهی قلم متن
تخمین مدت زمان مطالعهی مطلب:
شش دقیقه
رفتار Blazorهای پیش از داتنت 8 در مورد مدیریت حالت
پیش از دات نت 8، دو حالت عمده برای توسعهی برنامههای Blazor وجود داشت: Blazor Server و Blazor WASM. در هر دو حالت، طول عمر سیستم تزریق وابستگیهای ایجاد و مدیریت شدهی توسط Blazor، معادل طول عمر برنامهاست.
در برنامههای Blazor Server، طول عمر سیستم تزریق وابستگیها، توسط ASP.NET Core قرار گرفتهی بر روی سرور مدیریت شده و نمونههای ایجاد شدهی سرویسهای توسط آن، به ازای هر کاربر متفاوت است. بنابراین اگر طول عمر سرویسی در اینجا به صورت Scoped تعریف شود، این سرویس فقط یکبار در طول عمر برنامه، به ازای یک کاربر جاری برنامه، تولید و نمونه سازی میشود. در این مدل برنامهها، سرویسهایی با طول عمر Singleton، بین تمام کاربران به اشتراک گذاشته میشوند. به همین جهت است که در این نوع برنامهها، مدیریت سرویس Context مخصوص EF-Core نکات خاصی را به همراه دارد. چون اگر بر اساس سیستم پیشفرض تزریق وابستگیها و طول عمر Scoped این سرویس عمل شود، یک Context فقط یکبار بهازای یک کاربر، یکبار نمونه سازی شده و تا پایان طول عمر برنامه، بدون تغییر زنده نگه داشته میشود؛ در حالیکه عموم توسعه دهندگان EF-Core تصور میکنند سرویسهای Scoped، پس از پایان یک درخواست، پایان یافته و Dispose میشوند، اما در اینجا پایان درخواستی نداریم. یک اتصال دائم SignalR را داریم و تا زمانیکه برقرار است، یعنی برنامه زندهاست. بنابراین در برنامههای Blazor Server، سرویسهای Scoped، به ازای هر کاربر، همانند Singleton رفتار میکنند (در سراسر برنامه به ازای یک کاربر در دسترس هستند) و سرویسهایی از اساس Singleton، بین تمام کاربران به اشتراک گذاشته میشوند.
در برنامههای Blazor WASM، طول عمر سیستم تزریق وابستگیها، توسط برنامهی وباسمبلی در حال اجرای بر روی مرورگر مدیریت میشود. یعنی مختص به یک کاربر بوده و طول عمر آن وابستهاست به طول عمر برگهی جاری مرورگر. بنابراین دراینجا بین سرویسهای Scoped و Singleton، تفاوتی وجود ندارد و همانند هم رفتار میکنند (هر دو مختص به یک کاربر و وابسته به طول عمر برگهی جاری هستند).
در هیچکدام از این حالتها، امکان دسترسی به HttpContext وجود ندارد (نه داخل اتصال دائم SignalR برنامههای Blazor Server و نه داخل برنامهی وباسمبلی در حال اجرای در مرورگر). اطلاعات بیشتر
بنابراین در این برنامهها برای نگهداری اطلاعات کاربر لاگین شدهی به سیستم و یا سایر اطلاعات سراسری برنامه، عموما از سرویسهایی با طول عمر Scoped استفاده میشود که در تمام قسمتهای برنامه به ازای هر کاربر، قابل دسترسی هستند.
رفتار Blazor 8x در مورد مدیریت حالت
هرچند دات نت 8 به همراه حالتهای رندر جدیدی است، اما هنوز هم میتوان برنامههایی کاملا توسعه یافته بر اساس مدلهای قبلی Blazor Server و یا Blazor WASM را همانند داتنتهای پیش از 8 داشت. بنابراین اگر تصمیم گرفتید که بجای استفاده از جزیرههای تعاملی، کل برنامه را به صورت سراسری تعاملی کنید، همان نکات قبلی، در اینجا هم صادق هستند و از لحاظ مدیریت حالت، تفاوتی نمیکنند.
اما ... اگر تصمیم گرفتید که از حالتهای رندر جدید استفاده کنید، مدیریت حالت آن متفاوت است؛ برای مثال دیگر با یک سیستم مدیریت تزریق وابستگیها که طول عمر آن با طول عمر برنامهی Blazor یکی است، مواجه نیستیم و حالتهای زیر برای آنها متصور است:
حالت رندر: صفحات رندر شدهی در سمت سرور یا Server-rendered pages
مفهوم: یک صفحهی Blazor که در سمت سرور رندر شده و HTML نهایی آن به سمت مرورگر کاربر ارسال میشود. در این حالت هیچ اتصال SignalR و یا برنامهی وباسمبلی اجرا نخواهد شد.
عواقب: طول عمر سرویسهای Scoped، بهمحض پایان رندر صفحه در سمت سرور، پایان خواهند یافت.
بنابراین در این حالت طول عمر یک سرویس Scoped، بسیار کوتاه است (در حد ابتدا و انتهای رندر صفحه). همچنین چون برنامه در سمت سرور اجرا میشود، دسترسی کامل و بدون مشکلی را به HttpContext دارد.
صفحات SSR، بدون حالت (stateless) هستند؛ به این معنا که حالت کاربر در بین هدایت به صفحات مختلف برنامه ذخیره نمیشود. به آنها میتوان از این لحاظ بهمانند برنامههای MVC/Razor pages نگاه کرد. در این حالت اگر میخواهید حالت کاربران را ذخیره کنید، استفاده از کوکیها و یا سشنها، راهحل متداول اینکار هستند.
حالت رندر: صفحات استریمی (Streamed pages)
مفهوم: یک صفحهی Blazor که در سمت سرور رندر شده و قطعات آماده شدهی HTML آن به صورت استریمی از دادهها، به سمت مرورگر کاربر ارسال میشوند. در این حالت هیچ اتصال SignalR و یا برنامهی وباسمبلی اجرا نخواهد شد.
عواقب: طول عمر سرویسهای Scoped، بهمحض پایان رندر صفحه در سمت سرور، پایان خواهند یافت.
بنابراین در این حالت طول عمر یک سرویس Scoped، بسیار کوتاه است (در حد ابتدا و انتهای رندر صفحه). همچنین چون برنامه در سمت سرور اجرا میشود، دسترسی کامل و بدون مشکلی را به HttpContext دارد.
حالت رندر: Blazor server page
مفهوم: یک صفحهی Blazor Server که یک اتصال دائم SignalR را با سرور دارد.
عواقب: طول عمر سرویسهای Scoped، معادل طول عمر اتصال SignalR است و با قطع این اتصال، پایان خواهند یافت. این نوع برنامهها اصطلاحا stateful هستند و از لحاظ دسترسی به حالت کاربر، تجربهی کاربری همانند یک برنامهی دسکتاپ را ارائه میدهند.
در این نوع برنامهها و درون اتصال SignalR، دسترسی به HttpContext وجود ندارد.
حالت رندر: Blazor wasm page
مفهوم: صفحهای که به کمک فناوری وباسمبلی، درون مرورگر کاربر اجرا میشود.
عواقب: طول عمر سرویسهای Scoped، معادل طول عمر برگه و صفحهی جاری است و با بسته شدن آن، پایان میپذیرد. این نوع برنامهها نیز اصطلاحا stateful هستند و از لحاظ دسترسی به حالت کاربر، تجربهی کاربری همانند یک برنامهی دسکتاپ را ارائه میدهند (البته فقط درون مروگر کاربر).
در این نوع برنامهها، دسترسی به HttpContext وجود ندارد.
حالت رندر: جزیرهی تعاملی Blazor Server و یا Blazor server island
مفهوم: یک کامپوننت Blazor Server که درون یک صفحهی دیگر (که عموما از نوع SSR است) قرار گرفته و یک اتصال SignalR را با سرور برقرار میکند.
عواقب: طول عمر سرویسهای Scoped، معادل طول عمر اتصال SignalR است و با قطع این اتصال، پایان خواهند یافت؛ برای مثال کاربر به صفحهای دیگر در این برنامه مراجعه کند. بنابراین این نوع کامپوننتها هم تا زمانیکه کاربر در صفحهی جاری قرار دارد، stateful هستند.
در این نوع برنامهها و درون اتصال SignalR، دسترسی به HttpContext وجود ندارد.
حالت رندر: جزیرهی تعاملی Blazor WASM و یا Blazor wasm island
مفهوم: یک کامپوننت Blazor WASM که درون یک صفحهی دیگر (که عموما از نوع SSR است) توسط فناوری وباسمبلی، درون مرورگر کاربر اجرا میشود.
عواقب: طول عمر سرویسهای Scoped، معادل مدت زمان فعال بودن صفحهی جاری است. به محض اینکه کاربر به صفحهای دیگر مراجعه و این کامپوننت دیگر فعال نباشد، طول عمر آن خاتمه خواهد یافت. بنابراین این نوع کامپوننتها هم تا زمانیکه کاربر در صفحهی جاری قرار دارد، stateful هستند (البته این حالت درون مرورگر کاربر مدیریت میشود و نه در سمت سرور).
در این نوع برنامهها، دسترسی به HttpContext وجود ندارد.
نتیجهگیری
همانطور که مشاهده میکنید، در صفحات SSR، دسترسی کاملی به HttpContext سمت سرور وجود دارد (که البته کوتاه مدت بوده و با پایان رندر صفحه، خاتمه خواهد یافت؛ حالتی مانند صفحات MVC و Razor pages)، اما در جزایر تعاملی واقع در آنها، خیر.
مسالهی مهم در اینجا، مدیریت اختلاط حالت صفحات SSR و جزایر تعاملی واقع در آنها است. مایکروسافت جهت پیاده سازی اعتبارسنجی و احراز هویت کاربران در Blazor 8x و برای انتقال حالت به این جزایر، از دو روش Root-level cascading values و سرویس PersistentComponentState استفاده کردهاست که آنها را در دو قسمت بعدی، با توضیحات بیشتری بررسی میکنیم.
پیش از دات نت 8، دو حالت عمده برای توسعهی برنامههای Blazor وجود داشت: Blazor Server و Blazor WASM. در هر دو حالت، طول عمر سیستم تزریق وابستگیهای ایجاد و مدیریت شدهی توسط Blazor، معادل طول عمر برنامهاست.
در برنامههای Blazor Server، طول عمر سیستم تزریق وابستگیها، توسط ASP.NET Core قرار گرفتهی بر روی سرور مدیریت شده و نمونههای ایجاد شدهی سرویسهای توسط آن، به ازای هر کاربر متفاوت است. بنابراین اگر طول عمر سرویسی در اینجا به صورت Scoped تعریف شود، این سرویس فقط یکبار در طول عمر برنامه، به ازای یک کاربر جاری برنامه، تولید و نمونه سازی میشود. در این مدل برنامهها، سرویسهایی با طول عمر Singleton، بین تمام کاربران به اشتراک گذاشته میشوند. به همین جهت است که در این نوع برنامهها، مدیریت سرویس Context مخصوص EF-Core نکات خاصی را به همراه دارد. چون اگر بر اساس سیستم پیشفرض تزریق وابستگیها و طول عمر Scoped این سرویس عمل شود، یک Context فقط یکبار بهازای یک کاربر، یکبار نمونه سازی شده و تا پایان طول عمر برنامه، بدون تغییر زنده نگه داشته میشود؛ در حالیکه عموم توسعه دهندگان EF-Core تصور میکنند سرویسهای Scoped، پس از پایان یک درخواست، پایان یافته و Dispose میشوند، اما در اینجا پایان درخواستی نداریم. یک اتصال دائم SignalR را داریم و تا زمانیکه برقرار است، یعنی برنامه زندهاست. بنابراین در برنامههای Blazor Server، سرویسهای Scoped، به ازای هر کاربر، همانند Singleton رفتار میکنند (در سراسر برنامه به ازای یک کاربر در دسترس هستند) و سرویسهایی از اساس Singleton، بین تمام کاربران به اشتراک گذاشته میشوند.
در برنامههای Blazor WASM، طول عمر سیستم تزریق وابستگیها، توسط برنامهی وباسمبلی در حال اجرای بر روی مرورگر مدیریت میشود. یعنی مختص به یک کاربر بوده و طول عمر آن وابستهاست به طول عمر برگهی جاری مرورگر. بنابراین دراینجا بین سرویسهای Scoped و Singleton، تفاوتی وجود ندارد و همانند هم رفتار میکنند (هر دو مختص به یک کاربر و وابسته به طول عمر برگهی جاری هستند).
در هیچکدام از این حالتها، امکان دسترسی به HttpContext وجود ندارد (نه داخل اتصال دائم SignalR برنامههای Blazor Server و نه داخل برنامهی وباسمبلی در حال اجرای در مرورگر). اطلاعات بیشتر
بنابراین در این برنامهها برای نگهداری اطلاعات کاربر لاگین شدهی به سیستم و یا سایر اطلاعات سراسری برنامه، عموما از سرویسهایی با طول عمر Scoped استفاده میشود که در تمام قسمتهای برنامه به ازای هر کاربر، قابل دسترسی هستند.
رفتار Blazor 8x در مورد مدیریت حالت
هرچند دات نت 8 به همراه حالتهای رندر جدیدی است، اما هنوز هم میتوان برنامههایی کاملا توسعه یافته بر اساس مدلهای قبلی Blazor Server و یا Blazor WASM را همانند داتنتهای پیش از 8 داشت. بنابراین اگر تصمیم گرفتید که بجای استفاده از جزیرههای تعاملی، کل برنامه را به صورت سراسری تعاملی کنید، همان نکات قبلی، در اینجا هم صادق هستند و از لحاظ مدیریت حالت، تفاوتی نمیکنند.
اما ... اگر تصمیم گرفتید که از حالتهای رندر جدید استفاده کنید، مدیریت حالت آن متفاوت است؛ برای مثال دیگر با یک سیستم مدیریت تزریق وابستگیها که طول عمر آن با طول عمر برنامهی Blazor یکی است، مواجه نیستیم و حالتهای زیر برای آنها متصور است:
حالت رندر: صفحات رندر شدهی در سمت سرور یا Server-rendered pages
مفهوم: یک صفحهی Blazor که در سمت سرور رندر شده و HTML نهایی آن به سمت مرورگر کاربر ارسال میشود. در این حالت هیچ اتصال SignalR و یا برنامهی وباسمبلی اجرا نخواهد شد.
عواقب: طول عمر سرویسهای Scoped، بهمحض پایان رندر صفحه در سمت سرور، پایان خواهند یافت.
بنابراین در این حالت طول عمر یک سرویس Scoped، بسیار کوتاه است (در حد ابتدا و انتهای رندر صفحه). همچنین چون برنامه در سمت سرور اجرا میشود، دسترسی کامل و بدون مشکلی را به HttpContext دارد.
صفحات SSR، بدون حالت (stateless) هستند؛ به این معنا که حالت کاربر در بین هدایت به صفحات مختلف برنامه ذخیره نمیشود. به آنها میتوان از این لحاظ بهمانند برنامههای MVC/Razor pages نگاه کرد. در این حالت اگر میخواهید حالت کاربران را ذخیره کنید، استفاده از کوکیها و یا سشنها، راهحل متداول اینکار هستند.
حالت رندر: صفحات استریمی (Streamed pages)
مفهوم: یک صفحهی Blazor که در سمت سرور رندر شده و قطعات آماده شدهی HTML آن به صورت استریمی از دادهها، به سمت مرورگر کاربر ارسال میشوند. در این حالت هیچ اتصال SignalR و یا برنامهی وباسمبلی اجرا نخواهد شد.
عواقب: طول عمر سرویسهای Scoped، بهمحض پایان رندر صفحه در سمت سرور، پایان خواهند یافت.
بنابراین در این حالت طول عمر یک سرویس Scoped، بسیار کوتاه است (در حد ابتدا و انتهای رندر صفحه). همچنین چون برنامه در سمت سرور اجرا میشود، دسترسی کامل و بدون مشکلی را به HttpContext دارد.
حالت رندر: Blazor server page
مفهوم: یک صفحهی Blazor Server که یک اتصال دائم SignalR را با سرور دارد.
عواقب: طول عمر سرویسهای Scoped، معادل طول عمر اتصال SignalR است و با قطع این اتصال، پایان خواهند یافت. این نوع برنامهها اصطلاحا stateful هستند و از لحاظ دسترسی به حالت کاربر، تجربهی کاربری همانند یک برنامهی دسکتاپ را ارائه میدهند.
در این نوع برنامهها و درون اتصال SignalR، دسترسی به HttpContext وجود ندارد.
حالت رندر: Blazor wasm page
مفهوم: صفحهای که به کمک فناوری وباسمبلی، درون مرورگر کاربر اجرا میشود.
عواقب: طول عمر سرویسهای Scoped، معادل طول عمر برگه و صفحهی جاری است و با بسته شدن آن، پایان میپذیرد. این نوع برنامهها نیز اصطلاحا stateful هستند و از لحاظ دسترسی به حالت کاربر، تجربهی کاربری همانند یک برنامهی دسکتاپ را ارائه میدهند (البته فقط درون مروگر کاربر).
در این نوع برنامهها، دسترسی به HttpContext وجود ندارد.
حالت رندر: جزیرهی تعاملی Blazor Server و یا Blazor server island
مفهوم: یک کامپوننت Blazor Server که درون یک صفحهی دیگر (که عموما از نوع SSR است) قرار گرفته و یک اتصال SignalR را با سرور برقرار میکند.
عواقب: طول عمر سرویسهای Scoped، معادل طول عمر اتصال SignalR است و با قطع این اتصال، پایان خواهند یافت؛ برای مثال کاربر به صفحهای دیگر در این برنامه مراجعه کند. بنابراین این نوع کامپوننتها هم تا زمانیکه کاربر در صفحهی جاری قرار دارد، stateful هستند.
در این نوع برنامهها و درون اتصال SignalR، دسترسی به HttpContext وجود ندارد.
حالت رندر: جزیرهی تعاملی Blazor WASM و یا Blazor wasm island
مفهوم: یک کامپوننت Blazor WASM که درون یک صفحهی دیگر (که عموما از نوع SSR است) توسط فناوری وباسمبلی، درون مرورگر کاربر اجرا میشود.
عواقب: طول عمر سرویسهای Scoped، معادل مدت زمان فعال بودن صفحهی جاری است. به محض اینکه کاربر به صفحهای دیگر مراجعه و این کامپوننت دیگر فعال نباشد، طول عمر آن خاتمه خواهد یافت. بنابراین این نوع کامپوننتها هم تا زمانیکه کاربر در صفحهی جاری قرار دارد، stateful هستند (البته این حالت درون مرورگر کاربر مدیریت میشود و نه در سمت سرور).
در این نوع برنامهها، دسترسی به HttpContext وجود ندارد.
نتیجهگیری
همانطور که مشاهده میکنید، در صفحات SSR، دسترسی کاملی به HttpContext سمت سرور وجود دارد (که البته کوتاه مدت بوده و با پایان رندر صفحه، خاتمه خواهد یافت؛ حالتی مانند صفحات MVC و Razor pages)، اما در جزایر تعاملی واقع در آنها، خیر.
مسالهی مهم در اینجا، مدیریت اختلاط حالت صفحات SSR و جزایر تعاملی واقع در آنها است. مایکروسافت جهت پیاده سازی اعتبارسنجی و احراز هویت کاربران در Blazor 8x و برای انتقال حالت به این جزایر، از دو روش Root-level cascading values و سرویس PersistentComponentState استفاده کردهاست که آنها را در دو قسمت بعدی، با توضیحات بیشتری بررسی میکنیم.