Failed to load project file BlazorServer.App.csproj. C:\Program Files\dotnet\sdk\5.0.103\Sdks\Microsoft.NET.Sdk.Razor\build\netstandard2.0\Microsoft.NET.Sdk.Razor.Component.targets(107,5): Error: The specified task executable location "C:\Program Files\dotnet\dotnet.exe /M" is invalid.
کنترل DatePicker شمسی مخصوص Silverlight 4
using System; using System.Data.Entity; namespace UsingNgen { public class NgenDbContex : DbContext { } class Program { static void Main() { var nGenCtx = new NgenDbContex(); Console.WriteLine("Press a key to exit..."); Console.ReadKey(); } } }
بعد از ذخیره فایل، در پنجره بالا دکمهای به نام Open in WPA ظاهر میشود. WPA مخفف Windows Performance Analyzer میباشد. آن را کلیک کنید تا محیط آنالایزر باز شود.
حال در سمت چپ این پنجره انواع آنالایزرها را مشاهده میکنید. روی آنالایزر Computation کلیک کنید و از زیرمجموعهی آن، CPU Usage را انتخاب کنید. آمار مربوط به برنامه خودمان را در تصویر بالا مشاهده میکنید. کل برنامه 164 میلی ثانیه زمان برده و فایل Clr.dll حدود 47 میلی ثانیه و یک فایل clrjit.dll نیز برای تولید کد JIT وجود دارد. حال برای تسریع در عمل شروع، از تکنیک Ngen به صورت زیر استفاده میکنیم.
3- دوباره به نوار جستجوی ویندوز رفته و ابزار Developer Command Prompt for VsXXXX را با امتیاز دسترسی از نوع Admin اجرا کنید. XXXX نسخهی ویژوال استودیو میباشد.
حال به محل ذخیره فایل اجرایی برنامه رفته و دستور Ngen Install EntityFramework.dll را تایپ کنید تا یک ایمیج کد Native از entityframework.dll ساخته شود. دوباره ابزار Windows Performance Recorder را لود کرده و روی دکمه Start کلیک کنید و فایل اجرایی برنامه را اجرا نمایید. پس از اتمام عملیات ثبت جزئیات، آن را در Windows Performance Analyzer باز نمایید.
همانطور که مشاهده میکنید کل برنامه ما 89 میلی ثانیه زمان برده و Clr.dll 29 ثانیه و به جای clrjit.dll فایل EntityFramework به صورت native تولید شده است.
ایجاد یک پروژهی Blazor WASM جدید
یک پوشهی جدید دلخواه را به نام BlazorWasmSQLite ایجاد کرده و با اجرای دستور dotnet new blazorwasm، یک پروژهی Blazor Web Assembly خالی جدید را در آن آغاز میکنیم. همانطور که از دستور نیز مشخص است، این پروژه از نوع hosted که به همراه Web API هم هست، نمیباشد.
افزودن Context و مدل EF-Core به برنامه
مدل برنامه به صورت زیر در پوشهی Models آن قرار میگیرد:
namespace BlazorWasmSQLite.Models; public class Car { public int Id { get; set; } public string Brand { get; set; } public int Price { get; set; } }
using Microsoft.EntityFrameworkCore; using BlazorWasmSQLite.Models; namespace BlazorWasmSQLite.Data; public class ClientSideDbContext : DbContext { public DbSet<Car> Cars { get; set; } = default!; public ClientSideDbContext(DbContextOptions<ClientSideDbContext> options) : base(options) { } }
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> <ItemGroup> <!-- EF Core and Sqlite --> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" /> </ItemGroup> </Project>
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using BlazorWasmSQLite; using Microsoft.EntityFrameworkCore; using BlazorWasmSQLite.Data; var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.Add<App>("#app"); builder.RootComponents.Add<HeadOutlet>("head::after"); builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); // Sets up EF Core with Sqlite builder.Services.AddDbContextFactory<ClientSideDbContext>(options => options .UseSqlite($"Filename=DemoData.db") .EnableSensitiveDataLogging()); await builder.Build().RunAsync();
ثبت تعدادی رکورد در بانک اطلاعاتی
در ادامه سعی میکنیم در فایل Index.razor، تعدادی رکورد را به بانک اطلاعاتی اضافه کنیم:
@page "/" @using Microsoft.Data.Sqlite @using Microsoft.EntityFrameworkCore @using BlazorWasmSQLite.Data @using BlazorWasmSQLite.Models <PageTitle>Index</PageTitle> <h1>Hello, world!</h1> Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" /> @code { [Inject] private IDbContextFactory<ClientSideDbContext> _dbContextFactory { get; set; } = default!; protected override async Task OnInitializedAsync() { await using var db = await _dbContextFactory.CreateDbContextAsync(); await db.Database.EnsureCreatedAsync(); // create seed data if (!db.Cars.Any()) { var cars = new[] { new Car { Brand = "Audi", Price = 21000 }, new Car { Brand = "Volvo", Price = 11000 }, new Car { Brand = "Range Rover", Price = 135000 }, new Car { Brand = "Ford", Price = 8995 } }; await db.Cars.AddRangeAsync(cars); await db.SaveChangesAsync(); } await base.OnInitializedAsync(); } }
اولین سعی در اجرای برنامه
در ادامه سعی میکنیم تا برنامه را اجرا کنیم. با خطای زیر متوقف خواهیم شد:
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The type initializer for 'Microsoft.Data.Sqlite.SqliteConnection' threw an exception. System.TypeInitializationException: The type initializer for 'Microsoft.Data.Sqlite.SqliteConnection' threw an exception. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.DllNotFoundException: e_sqlite3 at SQLitePCL.SQLite3Provider_e_sqlite3.SQLitePCL.ISQLite3Provider.sqlite3_libversion_number()
رفع مشکل کار با SQLite با کامپایل ویژهی آن
برای دسترسی به کدهای native در Blazor WASM و مرورگر، باید آنها را توسط کامپایلر emcc به صورت زیر کامپایل کرد:
$ git clone https://github.com/cloudmeter/sqlite $ cd sqlite $ emcc sqlite3.c -shared -o e_sqlite3.o
مرحلهی بعد، معرفی این object file تولید شده به برنامه است. برای اینکار ابتدا باید dotnet workload install wasm-tools را نصب کرد (مهم). سپس به فایل csproj برنامه مراجعه کرده و فایل e_sqlite3.o را به آن معرفی میکنیم:
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly"> <ItemGroup> <!-- EF Core and Sqlite --> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="6.0.1" /> <NativeFileReference Include="Data\e_sqlite3.o" /> </ItemGroup> </Project>
سعی در اجرای مجدد برنامه
پس از نصب wasm-tools و ذکر NativeFileReference فوق، اکنون اگر برنامه را اجرا کنیم، برنامه بدون مشکل اجرا خواهد شد:
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: BlazorWasmSQLite.zip
اگر امروز با استفاده از دستور dotnet new console یک برنامهی کنسول را شروع کنیم، به یک فایل program.cs تقریبا خالی و یک فایل csproj. مرتبط میرسیم و ... همین! اما نیازهای واقعی ما در یک برنامهی کنسول، شامل این موارد هستند:
- نیاز به انجام تزریق وابستگیها
- نیاز به دسترسی به فایلهای کانفیگ؛ شبیه به برنامههای وب
- نیاز به کار با EF و مدیریت صحیح طول عمر Context آن
- مشخص بودن شماره نگارش دات نت و همچنین ابزارهای EF استفاده شده
- غنی سازی کامپایلر با یک سری آنالایزر و تنظیمات مخصوص آن جهت اعمال سخت گیریهای بیشتر!
- استفاده از مدیریت مرکزی بستههای نیوگت برای پروژههای مختلف در Solution
- نیاز به کار با HttpClient؛ آن هم به نحو صحیحی
- نیاز به دسترسی به سوئیچها و پارامترهای ارسالی به برنامهی کنسول از طریق خط فرمان
- نیاز به دسترسی به سیستم Logging؛ شبیه به برنامههای وب
- امکان انجام آزمونهای واحد و یکپارچگی درون حافظهای
تمام این موارد به صورت از پیش تنظیم شده، در قالب ارائه شدهی توسط این پروژه موجود هستند.
برای نصب آن، ابتدا مخزن کد فوق را clone کرده و سپس فایل register_template.cmd آنرا اجرا کنید. پس از آن دستور dotnet new dntconsole، جهت ایجاد پروژههای جدید مبتنی بر این قالب، در دسترس خواهد بود.
چک لیست تهیه یک برنامه ASP.NET MVC
پروژههای کوچک عموما دارای ساختاری مشابه تصویر ذیل میباشند:
این مورد، روش پیشنهادی در Angular Seed است و بدین صورت است که تعاریف ماژولها در فایل app.js انجام میگیرد. تعاریف و پیاده سازی تمام کنترلرها در فایل controller.js است. و همچنین دایرکتیوها و فیلترها و سرویسها هر کدام در فایلها جداگانه تعریف و پیاده سازی میشوند. این روش راه حلی سریع برای پروژههای کوچک با تعداد developerهای کم است. برای مثال زمانی که یک developer در حال ویرایش فایل controller.js است، از آن جا که فایل مورد نظر checkout خواهد شد در نتیجه سایر developerها امکان تغییر در فایل مورد نظر را نخواهند داشت. سورس فایلها به مرور زیاد خواهد شد و در نتیجه debug آن سخت میشود.
روش دوم
در این حالت تعاریف کنترلر ها، مدلها و سرویسها هرکدام در یک دایرکتوری مجزا قرار خواهد گرفت. برای هر view یک کنترلر و بنا بر نیاز مدل تعریف میکنیم. ساختار آن به صورت زیر میشود:
دایرکتیوها و فیلترها عموما در یک فایل قرار داده خواهند شد تا بنابر نیاز در جای مناسب رفرنس داده شوند. این روش ساختار مناسبتری نسبه به روش قبلی دارد اما دارای معایبی هم چون موارد زیر است:
»وابستگی بین فایلها مشخص نیست در نتیجه بدون استفاده از کتابخانه هایی نظیر requireJs با مشکل مواجه خواهید شد.
»refactoring کدها تا حدودی سخت است.
روش سوم
این ساختار مناسب برای پیاده سازی پروژهها به صورت ماژولار است و برای پروژههای بزرگ نیز بسیار مناسب است. در این حالت شما فایلهای مربوط به هر ماژول را در دایرکتوری خاص آن قرار خواهید داد. به صورت زیر:
همان طور که ملاحظه میکنید سرویس ها، کنترلرها و حتی مدلهای مربوط به هر بخش در یک مسیر جداگانه قرار میگیرند. علاوه بر آن فایل هایی که قابلیت اشتراکی دارند در مسیری به نام common وجود دارند تا بتوان در جای مناسب برای استفاده از آنها رفرنس داده شود. حتی اگر در پروژه خود فقط یک ماژول دارید باز سعی کنید از این روش برای مدیریت فایلهای خود استفاده نمایید. اگر با ngStart آشنایی داشته باشید به احتمال زیاد با این روش بیگانه نیستید.
بررسی چند نکته درباره کدهای مشترک
»اگر ماژولها وابستگی شدیدی به فایلها و سورسهای مشترک دارند باید اطمینان حاصل نمایید که این ماژولها فقط به اطلاعات مورد نیاز دسترسی دارند. این اصل interface segregation principle اصول SOLID است.
»توابعی که کاربرد زیادی دارند و اصطلاحا به عنوان Utility شناخته میشوند باید به rootScope$ اضافه شوند تا scopeهای وابسته نیز به آنها دسترسی داشته باشند. این مورد به ویژه باعث کاهش تکرار وابستگیهای مربوط به هر کنترلر میشود.
»برای جداسازی وابستگیهای بین دو component بهتر از eventها استفاده نمایید. AngularJs این امکان را با استفاده از سرویسهای on$ و emit$ و broadcast$ به راحتی میسر کرده است.
مشکل نصب به روز رسانیهای دات نت فریم ورک
اگر احتمالا آپدیتهای اخیر دات نت فریم ورک را نتوانستهاید نصب کنید و هربار پس از ری استارت کامپیوتر مجددا سر و کله برنامه نصاب پیدا میشود و نهایتا پیغام failed را دریافت میکنید، متاسفانه فقط یک راه حل دارد. حذف موارد موجود و نصب مجدد نگارش جدید آنها. برای حذف کلیه نگارشهای دات نت فریم ورک از برنامه زیر استفاده کنید:
سپس بهتر است از نصاب نگارش وب دات نت فریم ورک استفاده کنید. از این لحاظ که تمام به روز رسانیها را به همراه دارد و متفاوت است با نسخهی آفلاین آن.
مشکل نصب به روز رسانیهای سیلورلایت
اگر هنگام نصب به روز رسانی جدید سیلورلایت هر بار پیغام silverlight.msi File Missing را دریافت میکنید، مسیر زیر را از رجیستری ویندوز حذف کنید. سپس به روز رسانی سیلورلایت بدون مشکل نصب خواهد شد:
پ.ن.
من هر دو مشکل را با ویندوز سرور 2003 داشتم.
امکانات جدید سی شارپ 9
سی شارپ 9 امکانات و بهبودهای جدید را اضافه خواهد کرد :
- Records
- Init only setters
- Top-level statements
- Pattern matching enhancements
- Native sized integers
- Function pointers
- Suppress emitting localsinit flag
- Target-typed new expressions
- static anonymous functions
- Target-typed conditional expressions
- Covariant return types
- Extension
GetEnumerator
support forforeach
loops - Lambda discard parameters
- Attributes on local functions
- Module initializers
- New features for partial methods
این نسخه بر روی دات نت 5 پشتیبانی خواهد شد برای اطلاعات بیشتر ^