- محیط برنامه نویسی قدرتمند
- هسته اصلی کدهای همه اپلیکیشنها تولید شده شبیه به هم است
- نیازی به یادگیری زبانهای مربوط به هر پلتفرم را ندارید
- کم هزینه و زمان کمتر
- طراحی رابط گرافیکی سریع و منعطف به کمک HTML5 , CSS3
- برنامه نویسی آسان و سریع با javascript , Typescript
- قابلیت اجرا بر روی چندین پلتفرم مختلف(Android,iOS,Widnows Phone )
- قابلیت استفاده از فریمورکهای تحت وب مانند Bootstrap , Angular JS, ...
- قابلیت طراحی پلاگین برای ارتباط با سیستم عامل
- مناسب برای برای برنامههای چت و استفاد از وب سرویسها
- مناسب برای ساخت بازیهای آنلاین و آفلاین با تکنولوژیهای تحت وب
- راحتی کار با آن برای برنامه نویسان تحت وب
- نداشتن ابزار گزارش خطاهای مناسب؛ درنتیجه برطرف کردن خطاها خسته کننده خواهد بود .
- UI, UX اپلیکیشنها باید به نحوی باشد که کاربر حس کند با نرمافزارهای بومی گوشی کار میکند.
- کاهش سرعت اجرایی جزئی نسبت به سایر برنامهها (به دلیل استفاده از WebView)
- عدم دسترسی مستقیم به سیستم عامل و امکانات آن
- Node.js
- Git CLI
- Google Chrome
- Apache Ant
- Oracle Java JDK 7 (حتما نسخه x86 نصب شود)
- Android SDK
- SQLLite For Windows Runtime
- Apple iTunes
- node.js را از لینک مقابل دانلود کنید: اینجا (پیشنهاد میکنیم نسخهی x86 آن را نصب کنید)
- Google Chrome را نصب کنید
- Git Command Line Tools را نصب کنید و توجه کنید که در هنگام نصب، گزینه مربوط به افزودن Git را به مسیر Command Prompt شما، انتخاب کرده باشید.
- Apchage Ant را دانلود و در مسیری از سیستم خودتان قرار دهید.
- Java JDK 7 x86 را از لینک مشخص شده دانلود کنید و سپس عملیات نصب را انجام دهید.
- Android SDK را از آدرس مشحص شده دانلود کنید. پکیچهای مورد نیاز، به این SDK افزوده شده است. بعد از دانلود آن را در مسیری از سیستم خود قرار دهید.
- Apple iTunes و SQLite را دانلود و نصب کنید.
- اگر از ویندوز 7 استفاده میکنید ، WebSocket4Net را از لینک مقابل دانلود کنید ( اینجا ) و سپس فایل net45\Release\WebSocket4Net.dll در مسیر زیر کپی کنید:
%GIT_HOME%\cmd;C:\Program Files (x86)\nodejs\;%JAVA_HOME%\bin;%ANT_HOME%\bin; %ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools; C:\ProgramData\Oracle\Java\javapath;
نکته تکمیلی
تبدیل html به pdf با کیفیت بالا
using (var converter = new Converter()) { converter.ConvertToPdf(new ConvertUri(SourcePath), "output.pdf", new PageSettings(PaperFormat.A4) { DisplayHeaderFooter = true, HeaderTemplate = header, FooterTemplate = footer, PrintBackground = true, }); converter.ConvertToImage(new ConvertUri(tempSourcePath), "output.png", new PageSettings(PaperFormat.A6)); }
var header = """ <div class="text center" style="color: lightgray;border-bottom: solid lightgray 0.1px; width: 100%; font-family: 'Samim'; font-size:7px;"> <span class="title"></span> </div> """; var footer = """ <div class="text center" style="color: lightgray; font-family: 'Samim'; font-size:7px;"> <span class="pageNumber"></span>/<span class="totalPages"></span> </div> """;
var HTML = "<HTML code>"; using (Converter converter = new Converter()) using (MemoryStream stream = new MemoryStream()) { // This is necessary when running on Docker converter.AddChromeArgument("--no-sandbox"); // Create PDF out of HTML string converter.ConvertToPdf(html, stream, new ChromeHtmlToPdfLib.Settings.PageSettings()); // Return file to user return File(stream.ToArray(), MediaTypeNames.Application.Pdf, "Report.pdf"); }
کوکیها به اندازهی خود اینترنت قدیمی هستند و تا سالها، تنها گزینهی شخصی سازی تجربهی کاربری در وب و انتقال آن از یک صفحه به صفحهی دیگری بهشمار میآمدند؛ به این نوع کوکیها، First-party cookies هم میگویند و توسط خود سایت ارائه دهندهی محتوا و برنامهها، تنظیم میشوند. در مقابل آن، third-party cookies یا کوکیهای ثالث هم وجود دارند که از طریق دومین دیگری بجز دومین اصلی برنامه، ارائه و تنظیم میشوند؛ به همین جهت به آنها Cross-site cookies هم میگویند. یکی از اهداف کوکیهای ثالث، ردیابی فعالیت کاربران در بین سایتهای مختلف است و این روزها به علت سوء استفادههای زیادی که از آنها میشوند، یکی از وسایل به اشتراکگذاری و جمع آوری اطلاعات خصوصی کاربران شدهاند.
البته کوکیهای ثالث، کاربردهای مفیدی هم دارند؛ مانند امکان پیاده سازی لاگین و اعتبارسنجی یکپارچهی بین چندین برنامه که به آن SSO یا Single Sign On هم گفته میشود؛ نمونهی آن، استفاده از Identity server و یا OpenId dict در دنیای داتنت است.
اما ... در کل به علت مشکلات یاد شده، اکثر مرورگرها تصمیم به عدم پذیرش و پردازش آنها گرفتهاند. برای مثال مرورگر Safari سالها است که اینگونه کوکیها را بلاک میکند و یا مرورگر فایرفاکس، کوکیهای ثالث ردیابها را بلاک میکند و ... مرورگر کروم نیز تصمیم گرفتهاست، تا پایان سال 2024، به این جمع محلق شود. هرچند اخیرا اعلام کردهاند، بجای اینکه مرورگر کروم، راسا این کار را انجام دهد، قرار است امکان انتخاب این گزینه به خود کاربر واگذار شود (چون ... خود گوگل از این نوع کوکیها منتفع است!). البته این تصمیم، بهنظر W3C خوش نیامده و اعلام کردهاند که این نوع کوکیها باید بروند!
روش آزمایش برنامهها برای بررسی تاثیر ممنوعیت کوکیهای ثالث
برای اینکه پیش از موعد، امکان آزمایش برنامهی خود را داشته باشید و بتوانید تاثیر ممنوعیت بکارگیری کوکیهای ثالث را بررسی کنید، در مرورگر کروم به آدرس زیر مراجعه کرده:
chrome://flags/#test-third-party-cookie-phaseout
و سپس این گزینه را فعال کنید و یا روش دوم فعالسازی آن، اجرای مرورگر کروم با سوئیچ test-third-party-cookie-phaseout-- از طریق خط فرمان است.
کدام برنامهها با ممنوعیت کوکیهای ثالث مشکل پیدا میکنند؟
اگر برنامهی SSO شما، مبتنی بر اعتبارسنجی یکپارچهی از نوع implicit flow است، حتما مشکل پیدا میکنید. در این حالت بهتر است به نوع امنتر authorization flow + PKCE مهاجرت کنید.
علت مسدود شدن نوع اعتبارسنجی و احراز هویت implicit flow که در برنامههای تک صفحهای وب (SPA/single-page apps) مرسوم است، شباهت بسیار زیاد آن به کاری است که ردیابهای اینترنتی انجام میدهند. در اینحالت، سایتهای ثالث، یک iframe مخفی را در پشت صحنه، درون سایت جاری باز کرده و توسط آن شروع به استفادهی از امکانات مرتبط با کوکیها میکنند. این الگو دقیقا همان کاری است که توسط implicit flow هم انجام میشود. بنابراین مرورگری که کوکیهای ثالث از این دست را مسدود میکند، قابلیت اعتبارسنجی یکپارچهی برنامههای SPA را هم غیرفعال خواهد کرد.
معرفی کتابخانه Loader برای بارگذاری JS و CSS
پیش از دات نت 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 استفاده کردهاست که آنها را در دو قسمت بعدی، با توضیحات بیشتری بررسی میکنیم.
آیا با وجود سیاماس فروشگاهی قدرتمندی مثل nopCommerce یا SmartStore آیا منطقی است که ما دوباره خودمان از صفر کد بزنیم؟
نکتهای در مورد مدیریت طول عمر اشیاء در حالت HybridHttpOrThreadLocalScoped در برنامههای دسکتاپ
An item with the same key has already been added.
_uow.Update(employee, x => x.OwnedCollection(y => y.RemainingLessons));