نظرات مطالب
فلسفه وجودی Path.Combine

یک نکته‌ی تکمیلی: بین مسیرهای مطلق و نسبی در لینوکس و ویندوز، تفاوت وجود دارد!

فرض کنید با استفاده از قطعه کد زیر، سعی در تبدیل یک مسیر نسبی را به مسیری مطلق، داریم:

private string GetAbsoluteApiUrl(string url)
    => Uri.TryCreate(url, UriKind.Absolute, out _) ? url : NavigationManager.ToAbsoluteUri(url).ToString();

این قطعه کد در ویندوز بدون مشکل کار می‌کند. برای مثال اگر مسیر api/test/ را به آن معرفی کنیم، آن‌را تبدیل به یک مسیر مطلق شروع شده‌ی با آدرس دامنه‌ی سایت می‌کند. اما ... این قطعه کد در لینوکس کار نمی‌کند! چون مسیر api/test/ در لینوکس، یک مسیر مطلق به‌شمار می‌رود! برای رفع این مشکل، قرار است چنین API ای در آینده اضافه شود:

new Uri("/foo", new UriCreationOptions { AllowImplicitFilePaths = false });

نظرات مطالب
C# 8.0 - Pattern Matching
بهبود «Property Patterns معرفی شده‌ی در C# 8.0» در C# 10.0

در C# 8.0 برای بررسی خواص تو در تو باید از الگوی زیر استفاده کرد:
....{property: {subProperty: pattern}}....
که این الگو در C# 10.0 به صورت زیر ساده شده‌است:
....{property.subProperty: pattern}....

یک مثال:
رکورد زیر را در نظر بگیرید:
public record TestRec(string name, string surname);
روش پیشین دسترسی به خاصیت طول name به صورت زیر است:
string TakeFourSymbols(TestRec obj) => obj switch
{
    TestRec { name: {Length: > 4} } rec => rec.name.Substring(0,4),
    // ...
};
که اکنون در C# 10.0 کمی متداول‌تر و ساده‌تر شده‌است:
string TakeFourSymbols(TestRec obj) => obj switch
{
    TestRec { name.Length: > 4 } rec => rec.name.Substring(0,4),
    // ...
};
نظرات مطالب
C# 6 - String Interpolation
معرفی «Constant interpolated strings» در C# 10.0

C# 10.0 به همراه تغییر و بهبود جزئی در مورد interpolated strings است. تا پیش از آن، امکان تعریف یک interpolated strings به صورت const وجود نداشت؛ اما اکنون این محدودیت برطرف شده‌است و قطعه کد زیر مجاز است:
const string constStrFirst = "FirstStr";
const string summaryConstStr = $"SecondStr {constStrFirst}";

محدودیت: این نکته تنها در مورد const string‌ها صادق است. برای مثال اگر از const char استفاده شود:
const char a = 'a';
const string constStrFirst = "FirstStr";
const string summaryConstStr = $"SecondStr {constStrFirst} {a}";
با خطای زیر مواجه می‌شویم:
// Error CS0133
// The expression being assigned to
// 'summaryConstStr' must be constant
نظرات مطالب
ارسال ایمیل در ASP.NET Core
- اگر این کتابخانه برای شما مفید نیست؛ از آن استفاده نکنید. ما راه حل دیگری نداریم. جای دیگری هم چیزی دیگری پیدا نمی‌کنید که در اساس با این راه حل متفاوت باشد.
- هدف از await را بهتر است در دوره‌ای که معرفی کردم (مبانی Async در C# 5) مطالعه کنید؛ چون به نظر آشنایی با آن ندارید. وجود آن نه مشکلی است و نه ربطی به قفل کردن UI دارد. البته اگر به نحو نادرستی مورد استفاده قرار گیرد، می‌تواند باعث قفل شدن UI هم شود که در آن سری با مثال بررسی شده.
- جائیکه HttpContext وجود ندارد، از آن استفاده نکنید. قالب رشته‌ای نهایی را به نحو دیگری تولید کنید.
- در این سایت برای تک ایمیل‌ها، از روش استفاده از سرویس‌های ارسال ایمیلی مانند مطلب جاری استفاده می‌شود (مانند ایمیلی که هم اکنون جهت اطلاع رسانی دریافت پاسخی به شما ارسال شد). برای ایمیل‌های با تعداد بالا از کتابخانه‌ی «DNT Scheduler» استفاده می‌شود که نسخه‌ی Core هم دارد. در Taskهایی که در اینجا تعریف می‌شوند، از بانک اطلاعاتی کوئری بگیرید و پارامترها را از آن‌ها استخراج کنید (در زمان‌هایی مشخص کوئری می‌گیرید که آیا زمان ارسال ایمیل هست یا خیر؟ اگر بله اطلاعات بیشتر را از بانک اطلاعاتی دریافت و استفاده کنید). از این لحاظ محدودیتی ندارد. مطلب «انجام کارهای پس‌زمینه» هم که عنوان شد نمونه‌ی دیگری از این نوع پیاده سازی‌ها است؛ جهت آشنایی بیشتر.
نظرات مطالب
پشتیبانی توکار از ایجاد کلاس‌های Singleton از دات نت 4 به بعد
- مبحثی که در اینجا مطرح شده، مرتبط با حالت‌های عدم استفاده‌ی از سیستم تزریق وابستگی‌ها است. البته می‌توان این نوع Container‌ها را در حالت «service locator»، در همه‌جا استفاده کرد و محدودیتی هم ندارند.
- اگر از یک سیستم تزریق وابستگی‌ها استفاده می‌کنید، مطلب جاری را فراموش کنید. یک کلاس معمولی را ایجاد کرده و یک اینترفیس را از آن استخراج کنید (مانند همیشه و بسیار عادی). سپس این اینترفیس و کلاس پیاده سازی کننده‌ی آن‌را با «طول عمر» singleton به این IoC Container معرفی کنید (مهم نیست نام آن IoC Container چیست. این روش همه جا کار می‌کند). اکنون چون مدیریت طول عمر این سرویس توسط IoC container مورد استفاده کنترل می‌شود، می‌توانید در سازنده‌ی آن تمام سرویس‌های دیگر را هم تزریق کرده (مانند تمام سرویس‌های دیگر تعریف شده) و استفاده کنید؛ چون وهله سازی و مدیریت طول عمر آن توسط خود Container مدیریت می‌شود.
- استفاده و یا تعریف متدهای Async در اینجا هیچ تفاوتی با قبل ندارد. همان امضای متدهای Task دار و در صورت نیاز async دار را ارائه دهید.

یک نکته: تزریق وابستگی‌ها در سازنده‌ی کلاس‌هایی با طول عمر singleton یکسری نکات خاص خودشان را دارند.
نظرات مطالب
سفارشی سازی ASP.NET Core Identity - قسمت پنجم - سیاست‌های دسترسی پویا
- مطلبی که در اینجا بحث شده، در مورد کوکی‌ها هست و سیستم مبتنی بر کوکی Identity. بحث دیگری تحت عنوان «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 بدون استفاده از سیستم Identity» مختص توکن‌ها است. 
- راه حل استانداردی که در این موارد برای JWTها استفاده می‌شود، تولید یک reference token است. مفهوم آن‌را در مطلب « امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت نهم- مدیریت طول عمر توکن‌ها » مطالعه کنید.
- بنابراین به صورت خلاصه می‌توانید بجای کل توکن، فقط یک Guid امن کوتاه را به سمت کاربر ارسال کنید. در این حالت باید اصل توکن طولانی را در بانک اطلاعاتی ذخیره کنید. سپس زمانیکه از کاربر Guid را دریافت می‌کنید (که اینجا reference token نام دارد)، توکن متناظر با آن‌را در بانک اطلاعاتی یافته و سپس مطابق نکته‌ی OnMessageReceived مطلب «اعتبارسنجی مبتنی بر JWT »، این توکن بازیابی شده‌ی از بانک اطلاعاتی را به عنوان context.Token معرفی کنید، تا به صورت خودکار از آن استفاده شود.
نظرات مطالب
مدیریت پیشرفته‌ی حالت در React با Redux و Mobx - قسمت هفتم - بررسی مفاهیم Mobx
- در Redux فقط یک store سراسری وجود دارد که در برگیرنده‌ی تمام اشیاء حالت‌های کامپوننت‌های مختلف برنامه است. علتش را هم در قسمت اول این سری مطالعه کنید که اصلا چرا به آن نیاز هست. علت انجام اینکارها چی هست. چه مشکلی وجود داشته که نیاز به store سراسری حس شده که بعد از آن مفاهیم مدیریت حالت سراسری ارائه شده‌اند.
- در Mobx می‌توان از چند store سراسری استفاده کرد. طراحی این storeها با خود شما است و برخلاف Redux که دسترسی مستقیمی به آن نیست، در اینجا می‌توان مستقیما خواص observable آن‌را تغییر داد و یا متدهایی را که به صورت action علامتگذاری شده‌اند، فراخوانی کرد و store را به حالت دیگری تغییر داد. یعنی در کل طراحی شیءگرای store در MobX، کاملا به برنامه نویس واگذار شده‌است. می‌توانید چندین store را به ازای اشیاء حالت کامپوننت‌های مختلف ایجاد کنید و سپس آن‌ها را به عنوان خاصیت‌های عمومی store اصلی که توسط Provider به لایه‌های زرین ارسال می‌کنید، معرفی کنید.
نظرات مطالب
انجام کارهای زمانبندی شده در برنامه‌های ASP.NET توسط DNT Scheduler
- بجای اینکار (اضافه و حذف کردن سرویس‌ها در زمان اجرای برنامه که با ری‌استارت برنامه در سمت سرور غیرمعتبر می‌شود)، بهتر است با توجه به اینکه این وظایف به صورت یک سرویس ثبت می‌شوند، یک سرویس سفارشی فعال یا غیرفعالسازی را تعریف کنید و آن‌را به سازنده‌ی این وظایف تزریق و استفاده کنید. سپس زمانیکه حلقه‌ی انجام وظایف به RunAsync رسید، در اینجا فرصت خواهید داشت تا سرویس سفارشی جدید تزریق شده را بررسی کرده و از فعال بودن یا نبودن این وظیفه مطلع شوید (برای مثال این سرویس بر اساس نامی که به آن ارسال می‌کنید، به بانک اطلاعاتی مراجعه کرده و روشن و یا خاموش بودن آن‌را بررسی کند. تنظیم بانک اطلاعاتی آن‌را هم واگذار کنید به قسمت مدیریتی برنامه).  
+ این نوع Taskهای پویا را باید در ابتدای کار برنامه و در کلاس آغازین آن، به صورت زیر معرفی کنید:
services.AddTransient<DoEnableProductTasks>();
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 5 - فعال سازی صفحات مخصوص توسعه دهنده‌ها
ارتقاء به ASP.NET Core 3.0

در کلاس آغازین برنامه‌های وب نگارش 3، بجای متد
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
اینبار متد زیر با معرفی IWebHostEnvironment مشاهده می‌شود (چون این نوع قبلی در دو اسمبلی Microsoft.Extensions.Hosting و Microsoft.AspNetCore.Hosting تعریف شده بوده، جهت رفع ابهام مجبور به این تغییرات شده‌اند):
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
و برای اینکه متدهای الحاقی مانند ()env.IsDevelopment  شناسایی شوند، نیاز به افزودن فضای نام زیر می‌باشد:
using Microsoft.Extensions.Hosting;
البته امضای قبلی، هنوز هم در نگارش 3 کار می‌کند؛ اما در نگارش‌های بعدی حذف خواهد شد.
به صورت خلاصه هرجائی در برنامه‌ی خود IHostingEnvironment دارید، باید به IWebHostEnvironment تبدیل شود. همچنین اگر از سرویس IApplicationLifetime در جائی استفاده کرده‌اید، باید به IHostApplicationLifetime تبدیل گردد.
نظرات مطالب
نوشتن Middleware سفارشی در ASP.NET Core
یکی از روش‌های مقابله با مشکل فوق استفاده از کلاس SemaphoreSlim می باشد که در NET Framework 4.0 معرفی شده و در فضای نام  System.Threading در دسترس می‌باشد.
اگر اکشن متد‌های شما به صورت async await ایجاد کرده اید بهتر هست  ابتدا کلاس زیر را ایجاد نمایید:
using System;
using System.Threading;
using System.Threading.Tasks;
 
namespace MyApp
{
    public class AsyncLock : IDisposable
    {
        private SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1, 1);
 
        public async Task<AsyncLock> LockAsync()
        {
            await _semaphoreSlim.WaitAsync();
            return this;
        }
 
        public void Dispose()
        {
            _semaphoreSlim.Release();
        }
    }
}
سپس به صورت زیر از آن استفاده کنید:
private static readonly AsyncLock _mutex = new AsyncLock();
 
using(await _mutex.LockAsync())
{
    // Critical section... You can await here!
}
در این صورت تمامی درخواست‌های به سمت سرور به ترتیب اجرا خواهند شد و دیگر مشکل فوق را نخواهیم داشت.