اشتراک‌ها
سری آموزشی Angular Material

Completed Angular Material tutorial with practical examples.
discussed points :
- angular material form design with validation
- angular material datatable
- popup dialog
- notification tool
- crud operations 

سری آموزشی Angular Material
اشتراک‌ها
بررسی server-side WebAssembly در دات نت 8

Experiments with the new WASI workload in .NET 8 Preview 4
.NET 8 adds a new "wasi-experimental" workload, replacing the earlier Wasi.Sdk. This is a step towards giving .NET native, built-in support for server-side WebAssembly scenarios.
This video shows how to get started, then demonstrates how .NET+WASI creates possibilities for new kinds of apps and new ways to use .NET. 

بررسی server-side WebAssembly در دات نت 8
اشتراک‌ها
مقایسه EntityFrameWork 6 (7) و NHibernate
 There is quite a bit of Entity Framework and NHibernate comparisons on the web already but all of them cover mostly the technical side of the question. In this post, I’ll compare these two technologies from a Domain Driven Design perspective. I’ll step through several code examples and show you how both of these ORMs let you deal with problems. 
مقایسه EntityFrameWork 6 (7) و NHibernate
مطالب
ذخیره سازی تنظیمات برنامه‌های ASP.NET Core در بانک اطلاعاتی به کمک Entity Framework Core
در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 7 - کار با فایل‌های config » با مقدمات کار با فایل‌های تنظیمات برنامه و تامین کننده‌های مختلف آن‌ها آشنا شدیم. در این مطلب قصد داریم یک نمونه‌ی سفارشی تامین کننده‌های تنظیمات برنامه را بر اساس دریافت و ذخیره سازی اطلاعات در بانک اطلاعاتی، تهیه کنیم.


ساختار موجودیت تنظیمات برنامه

تنظیمات برنامه با هر قالبی که تهیه شوند، دست آخر به صورت یک <Dictionary<string,string در برنامه پردازش شده و قابل دسترسی می‌شوند. بنابراین موجودیت معادل این Dictionary را به صورت زیر تعریف می‌کنیم:
namespace DbConfig.Web.DomainClasses
{
    public class ConfigurationValue
    {
        public int Id { get; set; }
        public string Key { get; set; }
        public string Value { get; set; }
    }
}


ساختار Context برنامه و مقدار دهی اولیه‌ی آن

پس از تعریف موجودیت تنظیمات برنامه، آن‌را به صورت زیر به Context برنامه معرفی می‌کنیم:
    public class MyAppContext : DbContext, IUnitOfWork
    {
        public MyAppContext(DbContextOptions options) : base(options)
        { }

        public virtual DbSet<ConfigurationValue> Configurations { set; get; }
همچنین، برای مقدار دهی مقادیر اولیه‌ی تنظیمات برنامه نیز اینبار می‌توان به کمک متد HasData، به صورت زیر عمل کرد:
        protected override void OnModelCreating(ModelBuilder builder)
        {
            // it should be placed here, otherwise it will rewrite the following settings!
            base.OnModelCreating(builder);

            // Custom application mappings
            builder.Entity<ConfigurationValue>(entity =>
            {
                entity.Property(e => e.Key).HasMaxLength(450).IsRequired();
                entity.HasIndex(e => e.Key).IsUnique();
                entity.Property(e => e.Value).IsRequired();
                entity.HasData(new ConfigurationValue
                {
                    Id = 1,
                    Key = "key-1",
                    Value = "value_from_ef_1"
                });
                entity.HasData(new ConfigurationValue
                {
                    Id = 2,
                    Key = "key-2",
                    Value = "value_from_ef_2"
                });
            });
        }

ایجاد یک IConfigurationSource سفارشی مبتنی بر بانک اطلاعاتی

انواع و اقسام تامین کننده‌های تنظیمات برنامه در پروژه‌های ASP.NET Core، در حقیقت یک پیاده سازی سفارشی از اینترفیس IConfigurationSource هستند. به همین جهت در ادامه یک نمونه‌ی مبتنی بر EF Core آن را تهیه می‌کنیم:
    public class EFConfigurationSource : IConfigurationSource
    {
        private readonly IServiceProvider _serviceProvider;

        public EFConfigurationSource(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }

        public IConfigurationProvider Build(IConfigurationBuilder builder)
        {
            return new EFConfigurationProvider(_serviceProvider);
        }
    }
در اینجا چون می‌خواهیم به IUnitOfWork دسترسی پیدا کنیم، IServiceProvider را به سازنده‌ی این تامین کننده تزریق کرده‌ایم. کار اصلی ساخت آن نیز در متد Build، با ارائه‌ی یک IConfigurationProvider سفارشی انجام می‌شود. اینجا است که اطلاعات را از بانک اطلاعاتی خوانده و در اختیار سیستم تنظیمات برنامه قرار می‌دهیم:
    public class EFConfigurationProvider : ConfigurationProvider
    {
        private readonly IServiceProvider _serviceProvider;

        public EFConfigurationProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
            ensureDatabaseIsCreated();
        }

        public override void Load()
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                var uow = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
                this.Data?.Clear();
                this.Data = uow.Set<ConfigurationValue>()
                               .AsNoTracking()
                               .ToList()
                               .ToDictionary(c => c.Key, c => c.Value);
            }
        }

        private void ensureDatabaseIsCreated()
        {
            using (var scope = _serviceProvider.CreateScope())
            {
                var uow = scope.ServiceProvider.GetRequiredService<IUnitOfWork>();
                uow.Migrate();
            }
        }
    }
در ConfigurationProvider فوق، متد Load، در آغاز برنامه فراخوانی شده و در اینجا فرصت داریم تا خاصیت this.Data آن‌را که از نوع <Dictionary<string,string است، مقدار دهی کنیم. بنابراین از serviceProvider تزریق شده‌ی در سازنده‌ی کلاس استفاده کرده و به وهله‌ای از IUnitOfWork دسترسی پیدا می‌کنیم. سپس بر این اساس تمام رکوردهای جدول متناظر با ConfigurationValue را دریافت و توسط متد ToDictionary، تبدیل به ساختار مدنظر خاصیت this.Data می‌کنیم.
در اینجا فراخوانی متد ensureDatabaseIsCreated را نیز مشاهده می‌کنید. کلاس EFConfigurationProvider در آغاز برنامه و پیش از هر عمل دیگری وهله سازی شده و سپس متد Load آن فراخوانی می‌شود. به همین جهت نیاز است یا پیشتر، بانک اطلاعاتی را توسط دستورات Migration ایجاد کرده باشید و یا متد ensureDatabaseIsCreated، اطلاعات Migration موجود را به بانک اطلاعاتی برنامه اعمال می‌کند.


معرفی EFConfigurationSource به برنامه

جهت معرفی ساده‌تر EFConfigurationSource تهیه شده، ابتدا یک متد الحاقی را بر اساس آن تهیه می‌کنیم:
    public static class EFExtensions
    {
        public static IConfigurationBuilder AddEFConfig(this IConfigurationBuilder builder,
            IServiceProvider serviceProvider)
        {
            return builder.Add(new EFConfigurationSource(serviceProvider));
        }
    }
سپس می‌توان این متد AddEFConfig را به صورت زیر به تنظیمات برنامه در کلاس Startup اضافه و معرفی کرد:
namespace DbConfig.Web
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddScoped<IUnitOfWork, MyAppContext>();
            services.AddScoped<IConfigurationValuesService, ConfigurationValuesService>();

            var connectionString = Configuration.GetConnectionString("SqlServerConnection")
                     .Replace("|DataDirectory|", Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "app_data"));
            services.AddDbContext<MyAppContext>(options =>
                    {
                        options.UseSqlServer(
                            connectionString,
                            dbOptions =>
                                {
                                    var minutes = (int)TimeSpan.FromMinutes(3).TotalSeconds;
                                    dbOptions.CommandTimeout(minutes);
                                    dbOptions.EnableRetryOnFailure();
                                });
                    });

            var serviceProvider = services.BuildServiceProvider();
            var configuration = new ConfigurationBuilder()
                                       .AddConfiguration(Configuration) // Adds all of the existing configurations
                                       .AddEFConfig(serviceProvider)
                                       .Build();
            services.AddSingleton<IConfigurationRoot>(sp => configuration); // Replace
            services.AddSingleton<IConfiguration>(sp => configuration); // Replace
در اینجا ابتدا نیاز است یک ConfigurationBuilder جدید را ایجاد کنیم تا بتوان AddEFConfig را بر روی آن فراخوانی کرد. در این بین، خود برنامه نیز تعدادی تامین کننده‌ی تنظیمات پیش‌فرض را نیز دارد که قصد نداریم سبب پاک شدن آن‌ها شویم. به همین جهت آن‌ها را توسط متد AddConfiguration، افزوده‌ایم. پس از تعریف این ConfigurationBuilder جدید، نیاز است آن‌را جایگزین IConfiguration و IConfigurationRoot پیش‌فرض برنامه کنیم که روش آن‌را در دو متد services.AddSingleton ملاحظه می‌کنید.
همچنین روش دسترسی به serviceProvider مورد نیاز AddEFConfig، توسط متد services.BuildServiceProvider نیز در کدهای فوق مشخص است. به همین جهت مجبور شدیم این تعریف را در اینجا قرار دهیم و گرنه می‌شد از کلاس Program و یا حتی سازنده‌ی کلاس Startup نیز استفاده کرد. مشکل این دو مکان عدم دسترسی به سرویس IUnitOfWork و سایر تنظیمات برنامه است.


آزمایش برنامه

اگر به قسمت «ساختار Context برنامه و مقدار دهی اولیه‌ی آن» مطلب جاری دقت کرده باشید، دو کلید پیش‌فرض در اینجا ثبت شده‌اند. به همین جهت در ادامه با تزریق سرویس IConfiguration به سازنده‌ی یک کنترلر، سعی در خواندن مقادیر آن‌ها خواهیم کرد:
namespace DbConfig.Web.Controllers
{
    public class HomeController : Controller
    {
        private readonly IConfiguration _configuration;

        public HomeController(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public IActionResult Index()
        {
            return Json(
                new
                {
                    key1 = _configuration["key-1"],
                    key2 = _configuration["key-2"]
                });
        }
با این خروجی:



به روز رسانی بانک اطلاعاتی برنامه و بارگذاری مجدد اطلاعات IConfiguration

فرض کنید توسط سرویسی، اطلاعات جدول ConfigurationValue را تغییر داده‌اید. نکته‌ی مهم اینجا است که اینکار سبب فراخوانی مجدد متد Load کلاس EFConfigurationProvider نخواهد شد و عملا این تغییرات در سراسر برنامه توسط تزریق اینترفیس IConfiguration قابل دسترسی نخواهند بود (مگر اینکه برنامه مجددا ری‌استارت شود). نکته‌ی به روز رسانی این اطلاعات به صورت زیر است:
    public class ConfigurationValuesService : IConfigurationValuesService
    {
        private readonly IConfiguration _configuration;

        public ConfigurationValuesService(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        private void reloadEFConfigurationProvider()
        {
            ((IConfigurationRoot)_configuration).Reload();
        }
در جائیکه نیاز است پس از به روز رسانی بانک اطلاعاتی، تنظیمات برنامه را نیز بارگذاری مجدد کنید، ابتدا اینترفیس IConfiguration را به سازنده‌ی آن تزریق کرده و سپس به نحو فوق، متد Reload را فراخوانی کنید. اینکار سبب می‌شود تا یکبار دیگری متد Load کلاس EFConfigurationProvider نیز فراخوانی شود که باعث بارگذاری مجدد تنظیمات برنامه خواهد شد.


کدهای کامل این مطلب را از اینجا می‌توانید دریافت کنید: EFCoreDbConfig.zip
نظرات مطالب
نرمال سازی اطلاعات کاربران در حین ثبت نام
نکته‌ای در مورد طراحی دیتابیس ASP.NET Core Identity
به جدول کاربران نگارش سوم ASP.NET Identity، دو فیلد NormalizedEmail و NormalizedUserName هم اضافه شده‌اند:

که الگوریتم پیش فرض نرمال سازی آن‌ها که فقط to upper case است، قابلیت سفارشی سازی هم دارد (برای مثال جهت اعمال نکات مطلب فوق).
علت وجود این فیلدهای اضافی سه مورد است:
- الف) کاربران پس از ویرایش ایمیل‌های خود، متوجه نرمالسازی نشوند. چون اصل ایمیل در فیلد Email ذخیره می‌شود.
- ب) با نرمال سازی بتوان جلوی مشکلات مطرح شده‌ی در مطلب جاری را گرفت و از ثبت چندین ایمیل یکسان و یا نام کاربری یکسان جلوگیری کرد.
- ج) برنامه نویس دیگر نیازی  ندارد تا توابع نرمالسازی را همواره به صورت دستی، در حین ویرایش اطلاعات کاربران اعمال کند. اکنون این نرمالسازی به صورت خودکار از سرویس ILookupNormalizer دریافت و اعمال می‌شود.
نظرات مطالب
استفاده از افزونه‌ی jsTree در ASP.NET MVC
- سمت کلاینت آن که اساسا وابستگی به فناوری سمت سرور خاصی ندارد و با PHP هم قابل استفاده‌است.
- کلیات پیاده سازی سمت سرور MVC5x آن هم با ASP.NET Core تقریبا یکی هست و تغییری نکرده.
- اگر نیاز به پیاده سازی با EF Core را داشته باشید مطلب «شروع به کار با EF Core 1.0 - قسمت 11 - بررسی رابطه‌ی Self Referencing» می‌تواند مفید باشد.
در کل همیشه بهتر است عنوان کنید، چکار کردید، چه مراحلی را طی کردید و به چه مشکلاتی برخوردید، تا پاسخ دقیق‌تری را دریافت کنید.
نظرات مطالب
آشنایی با Refactoring - قسمت 9
سلام ، 
اگر فرض کنیم RoleRepository مطلب جاری پیاده سازی منطق تجاری قسمت کاربران در یک پروژه‌ی ASP.NET MVC می‌باشد، این استثناء‌ها کجا باید مدیریت شوند ؟ در بدنه‌ی Controller ؟ 
به عبارتی دیگر بهتر است نوع بازگشتی لایه‌ی سرویس یک شیء باشد که موفقیت / عدم موفقیت عملیات به همراه پیغام خطا را بازگرداند یا اینکه در صورت صحیح نبودن روند مثلا تکراری بودن نام کاربری Exception ارسال شود و استفاده کننده از Service مثل Controller مسئولیت Handle کردن استثناء‌ها را بر عهده بگیرد ؟ 
مطالب
پشتیبانی از IE در برنامه‌های Angular
اگر یک برنامه‌ی Angular را به صورت پیش‌فرض در IE اجرا کنیم، یک چنین تصویری مشاهده خواهد شد:


برای اجرای برنامه توسط نگارش‌های مختلف IE می‌توانید برنامه‌ی IE Tester را نصب کنید.


مشکل چیست؟

مشکل عدم اجرای برنامه‌های Angular در IE، به قدیمی بودن موتور JavaScript آن بر می‌گردد؛ خصوصا در مورد توابع کار با آرایه‌ها. برای مثال در مورد کار با for..of هیچ نوع پشتیبانی از آن در IE وجود ندارد (و نخواهد داشت؛ با توجه به پایان دوره‌ی پشتیبانی آن):



چگونه پشتیبانی از ویژگی‌های جدید JavaScript را به مرورگر IE اضافه کنیم؟

Angular امکان افزودن کمبودهای موتور JavaScript پیش‌فرض IE را توسط کتابخانه‌ی core-js میسر کرده‌است که اصطلاحا به آن polyfills گفته می‌شود. برای این منظور فایل src\polyfills.ts را گشوده و تغییرات زیر را به آن اعمال کنید:
الف) در این فایل، هرجایی  import // وجود دارد، آن‌را تبدیل به import کنید (تمام importهایی که کامنت شده‌اند را از حالت کامنت خارج کنید).
ب) دو بسته‌ی زیر را نیز باید نصب کنید:
npm install --save classlist.js
npm install --save web-animations-js
البته اگر به کامنت‌های این فایل دقت کنید، نیاز به نصب این بسته‌ها نیز در آن عنوان شده‌است.


نتیجه‌ی نهایی پس از افزودن polyfills مخصوص IE

اکنون اگر مجددا برنامه را کامپایل و اجرا کنید، برنامه‌ی Angular بدون مشکل در IE اجرا خواهد شد:

نظرات اشتراک‌ها
چرا از آنگولار به ری اکت + ری داکس سوئیچ کردم!
- فسلفه React مبتنی بر مخلوط کردن جاوا اسکریپت و HTML با هم هست در فایل‌های JSX (نوشتن HTML با کدهای جاوا اسکریپت). به این صورت شما مزیت‌های ذاتی HTML و CSS را یکجا از دست می‌دید؛ چون دیگه نمی‌تونید HTML جدا یا CSS جدای از جاوا اسکریپت را داشته باشین. در حالیکه در Angular این دو یا این سه (TypeScript، HTML و CSS) از هم جدا هستند که مزیت آن دسترسی به انواع ادیتورهایی هست که بدون اینکه برای Angular نوشته شده باشند، در همان بدو معرفی آن، با آن سازگار هستند که سادگی توسعه را به همراه داره. شاید تولید کامپوننت‌های ساده React تولید شده با کدهای جاوا اسکریپتی ساده باشه، اما کمی که حجم آن بیشتر شد، کنترل و مدیریت این مخلوط، سخت‌تر و سخت‌تر میشه و به علاوه مخلوط کردن کدهای یک فریم ورک با HTML و CSS خیلی شبیه به PHP کلاسیک و یا ASP کلاسیک هست و این روزها کسی را پیدا نمی‌کنید که برای پروژه‌های واقعی حتی از PHP در حالت کلاسیک آن بدون یک فریم ورک جانبی استفاده کنه. در Angular از همان بدو امر مباحث طراحی ماژول‌ها، کامپوننت‌ها و جدا سازی کدها به صورت ذاتی طراحی شده‌اند.
- مزیت کار کردن با TypeScript در مقایسه با ES6 خالص در React، امکان دسترسی به کامپایل آفلاین هست و مباحث پیشرفته‌ی کامپایلر مانند tree-shaking (حذف کدهای مرده) و AOT (a head of time compilation) که سبب می‌شن هم حجم نهایی کمتری تولید شود و هم پیش از اجرای برنامه در مرورگر و سپس یافتن باگ‌های احتمالی در زمان اجرا، پیش از موعد و توسط کامپایلر این باگ‌ها گزارش شوند. اگر قصد داشته باشید به یک چنین کیفیت و بررسی کدی در React برسید، باید تعداد آزمون‌های واحد قابل توجهی را داشته باشین تا بتونید یافتن مشکلاتی را که کامپایلر TypeScript گوشزد می‌کند، شبیه سازی کنید. همچنین شما در TypeScript می‌تونید به تمام امکانات پیشرفته‌ی زبان جاوا اسکریپت (حتی پس از ES6) دسترسی داشته باشید، اما کد نهایی جاوا اسکریپتی تولید شده‌ی توسط آن‌را برای ES5 که تمام مرورگرها از آن پشتیبانی می‌کنند، تولید کنید که این هم خودش یک مزیت مهم هست. بنابراین TypeScript فقط یک static type checker ساده نیست.
- اینکه Angular یک فریم‌ورک هست به خودی خودش یک مزیت مهم هست نسبت به React که یک کتابخانه است و اجزای آن باید از منابع مختلفی تهیه شوند. فریم ورک یعنی به روز رسانی‌های منظم تمام اجزای آن توسط خود تیم Angular و سازگاری کامل و یک‌دست هر جزء با نگارش فعلی یا همان آخرین نگارش موجود. اگر با دنیای وابستگی‌های ثالث در یک پروژه‌ی واقعی کار کرده باشید به خوبی می‌دونید که هر چقدر تعداد آن‌ها کمتر باشند، نگهداری طولانی مدت آن پروژه آسان‌تر می‌شود؛ چون روزی ممکن است آن کتابخانه‌ی ثالث دیگر توسعه پیدا نکند، یا منسوخ شود یا دیرتر از آخرین نگارش ارائه شده به روز رسانی شود. مزیت داشتن یک فریم ورک یک‌دست، درگیر نشدن با این مسایل است؛ خصوصا اینکه عموما کتابخانه‌های ثالث کیفیتشون در حد کتابخانه‌ی اصلی نیست و اینکه مثلا خود تیم Angular ماژول روتر، اعتبارسنجی یا فرم‌های اون رو توسعه می‌ده، قطعا کیفیتشون از کتابخانه‌های ثالث دیگه بهتر هست.
- در مورد سرعت و کارآیی و حتی مصرف حافظه، مطابق  یک benchmarck خیلی معتبر، وضعیت Angular اندکی بهتر از React است؛ هرچند در کل از این لحاظ به هم نزدیک هستند.
- این مباحث انحصاری شدن و این‌ها هم در مورد محصولات سورس باز، زیاد مفهومی ندارند و بیشتر یکسری شعار ایدئولوژیک هست توسط کسانیکه حتی تغییر رفتار این شرکت‌ها را هم دنبال نمی‌کنند و منابع و ماخذی رو که مطالعه کردن مربوط به یک دهه قبل هست. 
نظرات مطالب
نمایش اشیاء موجود در View بر اساس دسترسی‌ها در ASP.NET MVC
- شبیه به این مفهوم در ASP.NET Core یک Tag Helper جدید هست به نام SecurityTrimmingTagHelper 
- در پروژه‌های MVC 5.x هم یک نمونه security trimming دیگر با پیاده سازی HTML Helperها هست؛ مانند Secure Link‌ها و یا یک مثال دیگر