C# Geeks (.NET)
334 subscribers
128 photos
1 video
98 links
Download Telegram
🏛️ مونولیت ماژولار چیست؟ معماری هوشمندانه‌ای که قبل از میکروسرویس باید بشناسید
همیشه بحث بوده: سادگی و یکپارچگی مونولیت یا انعطاف‌پذیری و قدرت میکروسرویس؟ اما اگه یه راه سومی وجود داشته باشه که بهترین مزایای هر دو رو داشته باشه چی؟
با معماری مونولیت ماژولار (Modular Monolith) آشنا بشید؛ رویکردی که سادگی مونولیت رو با نظم و مرزبندی میکروسرویس ترکیب می‌کنه.

1️⃣ مونولیت ماژولار به زبان ساده چیه؟ 🧱
تصور کنید به جای ساختن یه ساختمون غول‌پیکر یک‌تکه (مونولیت سنتی)، یا چندین ساختمون کاملاً جدا از هم (میکروسرویس)، شما یک مجتمع آپارتمانی بزرگ می‌سازید.
کل مجتمع یک واحد یکپارچه است، ولی داخلش به واحدهای مستقل و ایزوله با دیوارهای محکم تقسیم شده. این واحدها همون ماژول‌ها هستن (مثلاً ماژول پرداخت، ماژول کاربران). هر ماژول کارکردهای مرتبط به خودش رو گروه‌بندی می‌کنه و مرزهای مشخصی داره.
💡نکته کلیدی: این واحدها (ماژول‌ها) اتصال سستی (loosely coupled) با هم دارن و فقط از طریق یک API عمومی و مشخص با هم صحبت می‌کنن، نه اینکه در جزئیات پیاده‌سازی هم دخالت کنن.


انعطاف‌پذیری در عمل: فرض کنید در فصل تعطیلات، ماژول رزرو شما نیاز به منابع بیشتری داره. در این معماری، شما می‌تونید موقتاً همون ماژول رو به صورت مستقل دیپلوی کنید و بعداً دوباره به مونولیت اصلی برش گردونید!
2️⃣ چرا "Monolith First"؟ (حتی به گفته بزرگان!) 💡
با اینکه میکروسرویس‌ها خیلی محبوبن، پیچیدگی‌های سیستم‌های توزیع‌شده (Distributed Systems) رو به همراه دارن. برای همین، خیلی از متخصصان، از جمله مارتین فاولر، میگن:

"شما نباید یک پروژه جدید را با میکروسرویس‌ها شروع کنید، حتی اگر مطمئن باشید که اپلیکیشن شما به اندازه‌ای بزرگ خواهد شد که این کار ارزشش را داشته باشد."
حتی گوگل هم در مقالات تحقیقاتی جدیدش، به ترند مونولیت ماژولار پیوسته. دلیل این امر، چالش‌های ذاتی میکروسرویس‌هاست:
1️⃣ پرفورمنس: سربار شبکه و سریال‌سازی داده‌ها، عملکرد رو کاهش میده.
2️⃣ صحت: تضمین صحت یک سیستم توزیع‌شده بسیار دشواره.
3️⃣ مدیریت: شما باید چندین اپلیکیشن مختلف با چرخه‌های انتشار متفاوت رو مدیریت کنید.
4️⃣ بعدی APIهای منجمد: تغییر APIها بدون شکستن سرویس‌های دیگه، سخت میشه.
5️⃣ سرعت توسعه: یک تغییر کوچک در یک سرویس، ممکنه نیازمند تغییر و هماهنگی در چندین سرویس دیگه باشه.

حالا که فهمیدیم مونولیت ماژولار چیه و چرا یک انتخاب هوشمندانه‌ست، در قسمت بعدی این سری به صورت عمیق به مزایای مشخص اون می‌پردازیم و اون رو مستقیماً با میکروسرویس‌ها مقایسه می‌کنیم.

🔖 هشتگ‌ها:
#SoftwareArchitecture #CSharp #DotNet #Monolith #Microservices #Developer #CleanCode
⚖️ دوئل معماری: مزایای مونولیت ماژولار در برابر میکروسرویس‌ها

حالا بیاید ببینیم این معماری در عمل چه مزایای ملموسی داره و تفاوت اصلیش با میکروسرویس‌ها چیه.

1️⃣ مهم‌ترین مزایای مونولیت ماژولار

🚀 استقرار ساده‌شده:
برخلاف میکروسرویس‌ها که نیازمند زیرساخت و استراتژی‌های پیچیده هستن، یک مونولیت ماژولار به سادگی و به عنوان یک واحد دیپلوی میشه.

⚡️ پرفورمنس بالا:
ارتباط بین ماژول‌ها به صورت درون-فرآیندی (in-process) و مستقیمه. این یعنی هیچ تأخیر شبکه یا سربار سریال‌سازی داده‌ای که در میکروسرویس‌ها وجود داره، اینجا نیست.

💻 سرعت توسعه بالا:
شما با یک پایگاه کد واحد سر و کار دارید. این کار دیباگ کردن، تست و تجربه کلی توسعه رو به شدت ساده و سریع می‌کنه.

🔗 مدیریت تراکنش آسان:
مدیریت تراکنش‌ها در سیستم‌های توزیع‌شده یه کابوس واقعیه. اما در مونولیت ماژولار، چون ماژول‌ها می‌تونن از یک دیتابیس مشترک استفاده کنن، این کار خیلی ساده‌تره.

🛠️ پیچیدگی عملیاتی کمتر:
شما فقط یک اپلیکیشن رو مدیریت، مانیتور و دیپلوی می‌کنید، نه ده‌ها سرویس مختلف رو.

🌱 مسیر هموار به سمت میکروسرویس:
اگه در آینده نیاز شد، به راحتی می‌تونید یه ماژول رو از ساختار اصلی جدا کنید و به یه سرویس مستقل تبدیلش کنید! این بزرگترین مزیت بلندمدت این معماریه.

2️⃣ مقایسه نهایی: مونولیت ماژولار در برابر میکروسرویس‌ها

بزرگترین تفاوت در نحوه استقرار (Deployment) اون‌هاست. میکروسرویس‌ها مرزهای منطقی داخل یه مونولیت ماژولار رو به مرزهای فیزیکی ارتقا میدن.
• مونولیت ماژولار به شما میده:
انسجام بالا، اتصال سست، کپسوله‌سازی داده و تمرکز بر کارکردهای بیزینسی.

•میکروسرویس‌ها به شما میده:
تمام موارد بالا + دیپلوی مستقل، مقیاس‌پذیری مستقل و توانایی استفاده از پشته‌های فناوری (tech stacks) مختلف برای هر سرویس.

3️⃣حرف آخر: نقل قول طلایی 🎯

همونطور که سایمون براون میگه:
"میکروسرویس‌ها را به خاطر مزایایشان انتخاب کنید، نه به این دلیل که پایگاه کد مونولیت شما یک فاجعه است."


مونولیت ماژولار به شما اجازه میده ابتدا خانه‌ی خود را مرتب کنید و بعداً تصمیم بگیرید که آیا واقعاً به چندین خانه جداگانه نیاز دارید یا نه.
🤔 نظر شما چیه؟
شما تو پروژه‌هاتون تجربه کار با مونولیت ماژولار رو داشتید؟ به نظرتون بزرگترین مزیت یا چالش این معماری چیه؟[منبع]

🔖 هشتگ‌ها:
#SoftwareArchitecture #CSharp #DotNet #Monolith #Microservices #Developer #CleanCode
🏗 سازنده‌ها (Constructors) در #C: معمار آبجکت‌های شما

هر آبجکتی در #C یه "لحظه تولد" داره. اون لحظه، کدی اجرا میشه که آبجکت رو برای زندگی آماده می‌کنه. به این کد جادویی میگن سازنده (Constructor).

سازنده، اولین متدیه که موقع ساختن یک نمونه جدید از کلاس با کلمه کلیدی new اجرا میشه. امروز می‌خوایم با تمام زیر و بم این معماران آبجکت آشنا بشیم.

1️⃣ سازنده چیست و چطور کار می‌کند؟

سازنده شبیه یک متده، با این تفاوت که اسمش دقیقاً هم‌اسم خود کلاس هست و هیچ نوع خروجی‌ای (حتی void) نداره. کار اصلیش، مقداردهی اولیه فیلدها و آماده‌سازی آبجکته.
public class Panda
{
string _name; // فیلد

// این سازنده است
public Panda(string name)
{
_name = name; // کد مقداردهی اولیه
}
}

// ... نحوه استفاده
Panda p = new Panda("Petey"); // سازنده اینجا صدا زده میشه


💡نکته حرفه‌ای: برای سازنده‌های تک‌خطی، می‌تونید از سینتکس Expression-bodied استفاده کنید:
public Panda(string name) => _name = name;
ترفند this: اگه اسم پارامتر با اسم فیلد یکی بود، می‌تونید با کلمه کلیدی this به فیلد کلاس اشاره کنید:
public Panda(string name) => this.name = name;

2️⃣ اورلودینگ و زنجیره‌ای کردن سازنده‌ها (this):

شما می‌تونید چندین سازنده با ورودی‌های مختلف (Overloading) داشته باشید. برای جلوگیری از تکرار کد، یک سازنده می‌تونه اون یکی رو با کلمه کلیدی : this(...) صدا بزنه.
public class Wine
{
public decimal Price;
public int Year;

public Wine(decimal price)
{
Price = price;
}

// این سازنده، قبل از اجرای بدنه خودش، سازنده بالایی رو صدا میزنه
public Wine(decimal price, int year) : this(price)
{
Year = year;
}
}


3️⃣ تله‌ی سازنده پیش‌فرض! ⚠️

قانون مهم: کامپایلر #C فقط و فقط زمانی که شما هیچ سازنده‌ای در کلاس تعریف نکرده باشید، یه سازنده عمومی بدون پارامتر ( ()public MyClass) براتون میسازه.

به محض اینکه شما حتی یک سازنده (با یا بدون پارامتر) بنویسید، اون سازنده اتوماتیک حذف میشه و اگه بهش نیاز دارید، باید خودتون دستی بنویسیدش. این یکی از خطاهای رایج برای تازه‌کارهاست!

4️⃣ ترتیب اجرا: اول فیلدها، بعد سازنده

اگه فیلدهاتون مقدار اولیه دارن، این مقداردهی همیشه قبل از اجرای اولین خط کد در سازنده و به ترتیب تعریفشون در کلاس انجام میشه.
class Player
{
int shields = 50; // این اول اجرا میشه
int health = 100; // این دوم اجرا میشه

public Player()
{
// این سوم اجرا میشه
Console.WriteLine("Constructor executed!");
}
}


5️⃣ کاربرد حرفه‌ای: سازنده‌های private

چرا باید یه سازنده رو private کنیم؟ برای اینکه کنترل کامل ساخت آبجکت رو به دست بگیریم! این الگو (که بهش Factory Method میگن) به ما اجازه میده که منطق ساخت رو داخل یه متد استاتیک قرار بدیم. مثلا برای پیاده‌سازی الگوی Singleton یا برگردوندن آبجکت از یک Pool.
public class MyApiClien
{
// سازنده خصوصیه، پس کسی از بیرون نمی‌تونه new کنه
private MyApiClient() { }

// فقط از طریق این متد استاتیک میشه نمونه ساخت
public static MyApiClient Create()
{
// ... منطق پیچیده برای ساخت و کانفیگ ...
return new MyApiClient();
}
}

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #OOP #Constructor #BestPractices
ساخت آبجکت مثل یک حرفه‌ای: قدرت Object Initializers در #C


یادتونه قدیما برای ساختن و مقداردهی یه آبجکت، باید چند خط کد پشت سر هم می‌نوشتیم؟ این روش هم طولانیه و هم ممکنه باعث بشه مقداردهی بعضی پراپرتی‌ها رو فراموش کنیم.

سی‌شارپ یه راه حل خیلی شیک، مدرن و امن برای این کار داره: Object Initializers.

1️⃣ روش سنتی در برابر روش مدرن
فرض کنید این کلاس Bunny رو داریم:
public class Bunny
{
public string Name;
public bool LikesCarrots;
public bool LikesHumans;

public Bunny() {}
public Bunny(string n) => Name = n;
}

روش قدیمی و چند خطی: 👎
Bunny b1 = new Bunny();
b1.Name = "Bo";
b1.LikesCarrots = true;
b1.LikesHumans = false;

روش مدرن با Object Initializer: 👍
حالا با سینتکس {}، می‌تونیم تمام این کارها رو در یک دستور و به صورت خیلی خوانا انجام بدیم:
Bunny b2 = new Bunny 
{
Name = "Bo",
LikesCarrots = true,
LikesHumans = false
};


این قابلیت حتی با سازنده‌هایی که پارامتر دارن هم کار می‌کنه:
Bunny b3 = new Bunny("Bo") 
{
LikesCarrots = true,
LikesHumans = false
};


2️⃣ پشت صحنه چه خبره؟ (نکته حرفه‌ای) ⚙️
شاید فکر کنید این سینتکس فقط یه خلاصه نویسیه، ولی کامپایلر پشت صحنه یه کار هوشمندانه برای امنیت در برابر خطاها (Exception Safety) انجام میده.

اون اول آبجکت رو تو یه متغیر موقت میسازه و بعد پراپرتی‌ها رو ست می‌کنه. این کار تضمین می‌کنه که اگه وسط مقداردهی یکی از پراپرتی‌ها خطایی رخ بده، شما هیچوقت با یه آبجکت نصفه و نیمه و ناقص مواجه نمیشید!

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #OOP #CleanCode #BestPractices
🔬 کالبدشکافی آبجکت‌ها با Deconstructors در #C


تو پست قبلی دیدیم چطور با Object Initializers یه آبجکت رو به صورت شیک "بسازیم". حالا بیاید ببینیم چطور می‌تونیم یه آبجکت رو به همون زیبایی "بشکافیم" و اجزاش رو استخراج کنیم!

سی‌شارپ یه قابلیت مدرن و قدرتمند به اسم Deconstructor داره که دقیقاً برعکس سازنده (Constructor) عمل می‌کنه.

1️⃣ حالا Deconstructor چیست؟
این Deconstructor یه متد خاص به اسم Deconstruct هست که شما تو کلاستون تعریف می‌کنید. این متد، فیلدها و پراپرتی‌های کلاس شما رو به مجموعه‌ای از متغیرهای خروجی (out parameters) تبدیل می‌کنه.
public class Rectangle
{
public readonly float Width, Height;

public Rectangle(float width, float height)
{
Width = width;
Height = height;
}

// این متد Deconstructor ماست
public void Deconstruct(out float width, out float height)
{
width = Width;
height = Height;
}
}


2️⃣ جادوی سینتکس: کالبدشکافی در یک خط!
حالا که متد Deconstruct رو داریم، #C به ما یه سینتکس فوق‌العاده شیک و خوانا برای استفاده ازش میده:
var rect = new Rectangle(3, 4);

// جادو اینجا اتفاق میفته!
// این خط، متد Deconstruct رو صدا میزنه
(float width, float height) = rect;

Console.WriteLine($"Width: {width}, Height: {height}"); // خروجی: Width: 3, Height: 4
این سینتکس، کد شما رو به شدت تمیز و بیانگر می‌کنه.


3️⃣ ترفندهای خلاصه‌نویسی
این قابلیت چند تا ترفند برای خلاصه‌تر شدن هم داره:

استفاده از var:
// کامپایلر خودش نوع‌ها رو تشخیص میده
var (width, height) = rect;

نادیده گرفتن با _ (Discard):
اگه فقط به یکی از مقادیر نیاز دارید، می‌تونید اون یکی رو با _ نادیده بگیرید:
// ما اینجا فقط به ارتفاع نیاز داریم
var (_, height) = rect;

تخصیص به متغیرهای موجود:
اگه متغیرها رو از قبل دارید، دیگه نیازی به تعریفشون نیست:
float w, h;
(w, h) = rect;

🤔 حرف حساب و تجربه شما
شما تا حالا از Deconstructors تو کدهاتون استفاده کردید؟ به نظرتون بهترین کاربرد این قابلیت کجاست؟

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #ModernCSharp #CleanCode #BestPractices
جمع‌بندی 📝
معرفی فیلترهای کوئری نام‌دار در EF 10 یکی از محدودیت‌های دیرینه را برطرف می‌کند. شما اکنون می‌توانید:

🔹 چندین فیلتر را به یک انتیتی متصل کرده و آن‌ها را به صورت جداگانه مدیریت کنید.

🔹 فیلترهای خاصی را در یک کوئری LINQ با استفاده از IgnoreQueryFilters(["FilterName"]) به صورت انتخابی غیرفعال کنید.

🔹 الگوهای رایجی مانند حذف منطقی و چند-مستأجری را ساده‌سازی کنید.

فیلترهای کوئری نام‌دار می‌توانند به ابزاری قدرتمند برای تمیز نگه داشتن کوئری‌ها و کپسوله‌سازی منطق دامین شما تبدیل شوند.

آن‌ها را در نسخه پیش‌نمایش امتحان کنید و به این فکر کنید که چگونه می‌توانند پایگاه کد شما را ساده‌تر کنند.

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #EntityFrameWork #EF
🚀 جادوی async/await در #C:

برنامه‌نویسی غیرهمزمان به زبان ساده
تا حالا شده یه دکمه تو اپلیکیشن‌تون بزنید و کل برنامه برای چند ثانیه هنگ کنه و سفید بشه؟ 🥶 این اتفاق وقتی میفته که یه کار زمان‌بر (مثل دانلود فایل یا کوئری دیتابیس) رو به صورت همزمان (Synchronous) انجام میدید و "نخ" اصلی برنامه رو قفل می‌کنید.

راه حل این کابوس، برنامه‌نویسی غیرهمزمان (Asynchronous) با دو کلمه کلیدی جادویی async و await هست.

1️⃣ داستان سرآشپز صبور (آنالوژی) 👨‍🍳

برای درک این مفهوم، یه رستوران رو تصور کنید:

سرآشپز همزمان (Synchronous): 👎
شما سفارش استیک میدید. سرآشپز استیک رو روی گریل میذاره و همونجا وایمیسته و ۱۰ دقیقه بهش زل میزنه تا بپزه. تو این ۱۰ دقیقه، هیچ کار دیگه‌ای نمی‌تونه بکنه و بقیه مشتری‌ها گشنه می‌مونن. این یعنی قفل شدن برنامه!

سرآشپز غیرهمزمان (Asynchronous): 👍
شما سفارش استیک میدید. سرآشپز استیک رو روی گریل میذاره (await) و بلافاصله از آشپزخونه میاد بیرون و سفارش بقیه رو میگیره. اون یه "قول" (Task) داره که استیک در حال آماده شدنه. ۱۰ دقیقه بعد، وقتی استیک آماده شد، برمی‌گرده سراغش، کار رو تموم می‌کنه و به شما تحویل میده. تو این مدت، رستوران (برنامه) کاملاً فعال و پاسخگو بوده!

2️⃣ کلمات کلیدی جادویی: async, await, Task

این سه تا با هم کار می‌کنن:

• async:
یه برچسبه که به متد می‌زنیم و به کامپایلر میگیم: "هی، این متد ممکنه وسط کارش منتظر یه چیزی بمونه و غیرهمزمانه". این کلمه، اجازه استفاده از await رو داخل متد میده.

• Task / Task<T>:
"قول" یا "رسیدی" هست که متد async فوراً برمی‌گردونه.

• Task:
یعنی "قول میدم این کار رو تموم کنم." (برای متدهایی که خروجی ندارن).

• Task<T>:
یعنی "قول میدم این کار رو تموم کنم و یه نتیجه از نوع T بهت تحویل بدم."

• await:
قلب ماجراست! این کلمه رو قبل از صدا زدن یه متد async دیگه میذاریم و به برنامه میگه:

"اجرای این کار زمان‌بر رو شروع کن، و تا وقتی تموم میشه، کنترل رو به کسی که منو صدا زده برگردون تا اون بتونه به کاراش برسه! وقتی کارم تموم شد، از همین خط به بعد ادامه میدم."

3️⃣ مثال عملی: دانلود کردن یک فایل

روش بد (Synchronous) که باعث هنگ کردن برنامه میشه:
//  این متد نخ اصلی رو برای ۵ ثانیه قفل می‌کنه!
public void DownloadFile()
{
Thread.Sleep(5000); // شبیه‌سازی یک عملیات زمان‌بر و مسدودکننده
Console.WriteLine("Download complete.");
}


روش خوب (Asynchronous) با async/await:
//  این متد نخ اصلی رو آزاد می‌کنه و برنامه پاسخگو باقی می‌مونه
public async Task DownloadFileAsync()
{
// await کنترل رو به بیرون برمی‌گردونه و منتظر می‌مونه
await Task.Delay(5000); // شبیه‌سازی یک عملیات غیرهمزمان
Console.WriteLine("Download complete.");
}

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #Async #Await #Concurrency
📌در این مثال:

• کلید کش برای هر محصول منحصر به فرد است.

• اگر محصول در کش باشد، بلافاصله برگردانده می‌شود.

• اگر نباشد، متد factory برای گرفتن داده اجرا می‌شود.

• درخواست‌های همزمان دیگر برای همان محصول، منتظر پایان یافتن اولین درخواست می‌مانند.

تنظیم مستقیم ورودی‌های کش ✍️

گاهی اوقات نیاز دارید کش را مستقیماً به‌روزرسانی کنید، مانند پس از تغییر داده‌ها. متد SetAsync این کار را انجام می‌دهد:
app.MapPut("/products/{id}", async (int id, Product product, HybridCache cache) =>
{
// ابتدا دیتابیس را به‌روزرسانی کنید
await UpdateProductInDatabase(product);

// سپس کش را با انقضای سفارشی به‌روزرسانی کنید
var options = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromHours(1),
LocalCacheExpiration = TimeSpan.FromMinutes(30)
};

await cache.SetAsync(
$"product-{id}",
product,
options
);

return Results.NoContent();
});


استفاده از تگ‌های کش 🏷

تگ‌ها برای مدیریت گروه‌هایی از ورودی‌های کش مرتبط، قدرتمند هستند. شما می‌توانید چندین ورودی را به یکباره با استفاده از تگ‌ها نامعتبر کنید:
app.MapGet("/categories/{id}/products", async (...) =>
{
var tags = [$"category-{id}", "products"];

var products = await cache.GetOrCreateAsync(
$"products-by-category-{id}",
async token => { /* ... fetch products ... */ },
tags: tags,
cancellationToken: ct
);

return Results.Ok(products);
});

// Endpoint برای نامعتبر کردن تمام محصولات در یک دسته‌بندی
app.MapPost("/categories/{id}/invalidate", async (id, cache, ct) =>
{
await cache.RemoveByTagAsync($"category-{id}", ct);
return Results.NoContent();
});


📍تگ‌ها برای موارد زیر مفید هستند:


• نامعتبر کردن تمام محصولات در یک دسته‌بندی.

• پاک کردن تمام داده‌های کش شده برای یک کاربر خاص.

• رفرش کردن تمام داده‌های مرتبط هنگامی که چیزی تغییر می‌کند.

حذف ورودی‌های تکی 🗑

برای نامعتبرسازی مستقیم آیتم‌های خاص، از RemoveAsync استفاده کنید:
app.MapDelete("/products/{id}", async (int id, HybridCache cache) =>
{
// ابتدا از دیتابیس حذف کنید
await DeleteProductFromDatabase(id);

// سپس از کش حذف کنید
await cache.RemoveAsync($"product-{id}");

return Results.NoContent();
});


افزودن Redis به عنوان کش L2 🔥

برای استفاده از Redis به عنوان کش توزیع‌شده خود:
پکیج NuGet را نصب کنید:

Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
Redis و HybridCache را پیکربندی کنید:

// افزودن Redis
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "your-redis-connection-string";
});
// افزودن HybridCache - به طور خودکار از Redis به عنوان L2 استفاده خواهد کرد
builder.Services.AddHybridCache();


خلاصه 📝

HybridCache
کشینگ را در اپلیکیشن‌های NET. ساده می‌کند. این قابلیت، کشینگ سریع درون-حافظه‌ای را با کشینگ توزیع‌شده ترکیب می‌کند، از مشکلات رایج مانند cache stampede جلوگیری می‌کند، و هم در سیستم‌های تک-سروری و هم توزیع‌شده به خوبی کار می‌کند.

با تنظیمات پیش‌فرض و الگوهای استفاده اولیه شروع کنید - این کتابخانه طوری طراحی شده که استفاده از آن ساده باشد در حالی که مشکلات پیچیده کشینگ را حل می‌کند.

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #HybridCache
مدیریت متمرکز پکیج‌ها (CPM) در NET. : یک بار برای همیشه!


روزهایی رو به یاد میارم که مدیریت پکیج‌های NuGet در چندین پروژه یک دردسر واقعی بود. میدونید چی میگم - یه سولوشن بزرگ رو باز می‌کنی و می‌بینی هر پروژه از یه نسخه متفاوت از همون پکیج استفاده می‌کنه. اصلاً جالب نیست! 😫

بذارید بهتون نشون بدم که چطور مدیریت متمرکز پکیج‌ها (CPM) در NET. می‌تونه این مشکل رو یک بار برای همیشه حل کنه.

مشکلی که باید حل کنیم 💥
من اغلب با سولوشن‌هایی کار می‌کنم که پروژه‌های زیادی دارن. سولوشن‌هایی با ۳۰ یا بیشتر پروژه غیرمعمول نیستن. هر کدوم به پکیج‌های مشابهی مثل Serilog یا Polly نیاز دارن. قبل از CPM، پیگیری نسخه‌های پکیج یه افتضاح بود:

🔹 یک پروژه از Serilog 4.1.0 استفاده می‌کرد.

🔹 دیگری از Serilog 4.0.2.

🔹 و یه جوری، سومی از Serilog 3.1.1!

نسخه‌های مختلف می‌تونن رفتار متفاوتی داشته باشن که منجر به باگ‌های عجیبی میشه که پیدا کردنشون سخته. من ساعت‌های زیادی رو برای رفع مشکلات ناشی از عدم تطابق نسخه‌ها تلف کرده‌ام.

مدیریت متمرکز پکیج‌ها چگونه کمک می‌کند؟ 🎮

CPM
رو مثل یک مرکز کنترل برای تمام نسخه‌های پکیج‌تون در نظر بگیرید. به جای تنظیم نسخه‌ها در هر پروژه، اون‌ها رو یک بار در یک جا تنظیم می‌کنید. بعد، فقط به پکیجی که می‌خواید استفاده کنید، بدون مشخص کردن نسخه، ارجاع میدید. به همین سادگی!

برای استفاده از مدیریت متمرکز پکیج‌ها به این موارد نیاز دارید:


NuGet نسخه 6.2 یا جدیدتر

.NET SDK نسخه 6.0.300 یا جدیدتر

اگر از ویژوال استودیو استفاده می‌کنید، نسخه 2022 17.2 یا جدیدتر

راه‌اندازی آن 📁

اول، یک فایل به نام Directory.Packages.props در پوشه اصلی سولوشن خود ایجاد کنید:
<Project>
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<ItemGroup>
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Serilog" Version="4.1.0" />
<PackageVersion Include="Polly" Version="8.5.0" />
</ItemGroup>
</Project>

در فایل‌های پروژه‌تون، می‌تونید پکیج‌ها رو با استفاده از PackageReference بدون نسخه لیست کنید:
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="AutoMapper" />
<PackageReference Include="Polly" />
</ItemGroup>

همین! حالا تمام پروژه‌های شما از یک نسخه پکیج یکسان استفاده خواهند کرد.

✨️کارهای باحالی که می‌تونید انجام بدید
نیاز به نسخه‌ای متفاوت برای یک پروژه دارید؟ 🎯

مشکلی نیست! فقط این رو به فایل پروژه‌تون اضافه کنید:
<PackageReference Include="Serilog" VersionOverride="3.1.1" />

📍پراپرتی VersionOverride به شما اجازه میده نسخه خاصی که می‌خواید رو تعریف کنید.

یه پکیج رو تو همه پروژه‌ها می‌خواید؟ 🌍

اگه پکیج‌هایی دارید که هر پروژه‌ای بهشون نیاز داره، می‌تونید اون‌ها رو سراسری کنید. یک GlobalPackageReference در فایل props خود تعریف کنید:
<ItemGroup>
<GlobalPackageReference Include="SonarAnalyzer.CSharp" Version="10.3.0.106239" />
</ItemGroup>

حالا هر پروژه‌ای به طور خودکار این پکیج رو دریافت می‌کنه!

مهاجرت پروژه‌های موجود به CPM 🚚

1️⃣ فایل Directory.Packages.props رو در ریشه سولوشن ایجاد کنید.
2️⃣ تمام نسخه‌های پکیج رو از فایل‌های .csproj خود به اونجا منتقل کنید.
3️⃣ ویژگی Version رو از عناصر PackageReference حذف کنید.
4️⃣ سولوشن خود را بیلد کرده و هرگونه تداخل نسخه رو برطرف کنید.
5️⃣ قبل از کامیت کردن، به طور کامل تست کنید.

همچنین یه ابزار CLI به نام CentralisedPackageConverter وجود داره که می‌تونید برای اتوماتیک کردن مهاجرت ازش استفاده کنید.

چه زمانی باید از CPM استفاده کنید؟ 🤔
من دلیل قانع‌کننده‌ای برای استفاده نکردن پیش‌فرض از این قابلیت نمی‌بینم.
من توصیه می‌کنم از CPM استفاده کنید وقتی:

• پروژه‌های زیادی دارید که پکیج‌های مشترک دارن.

• از رفع باگ‌های مربوط به نسخه خسته شده‌اید.

• می‌خواید مطمئن بشید همه از نسخه‌های یکسان استفاده می‌کنن.

جمع‌بندی 📝
نکات من برای موفقیت با مدیریت متمرکز پکیج‌ها:


💡 وقتی CPM رو به یه سولوشن موجود اضافه می‌کنید، این کار رو در یک change/PR جداگانه انجام بدید.

💡 اگه نسخه‌ای رو override می‌کنید، یه کامنت بذارید که دلیلش رو توضیح بده.

💡 نسخه‌های پکیج خود را به طور منظم برای آپدیت‌ها چک کنید.

💡 فقط پکیج‌هایی رو سراسری کنید که واقعاً همه جا بهشون نیاز دارید.

🔖 هشتگ‌ها:
#CSharp #DotNet #NuGet #DependencyManagement #BestPractices #CleanCode #Developer #VisualStudio
📖 سری آموزشی کتاب C# 12 in a Nutshell

👇کلیدواژه this در #C:

'خود' آبجکت کیست؟ در دنیای شیءگرایی، گاهی وقتا یه آبجکت نیاز داره به "خودش" اشاره کنه. ابزار #C برای این کار، کلمه کلیدی ساده ولی قدرتمند this هست. this در واقع ضمیر "من" برای یک آبجکته و به نمونه فعلی (current instance) خودش اشاره می‌کنه.

1️⃣ کاربرد اول: رفع ابهام (Disambiguation)
این رایج‌ترین کاربرد this هست. وقتی اسم پارامتر سازنده، هم‌اسم یکی از فیلدهای کلاس باشه، برای اینکه به کامپایلر بفهمونیم منظورمون فیلد کلاسه، از this استفاده می‌کنیم.
public class Test
{
private string name;
public Test(string name)
{
// this.name به فیلد کلاس اشاره داره
// name به پارامتر ورودی اشاره داره
this.name = name;
}
}


2️⃣ کاربرد دوم: پاس دادن خودِ آبجکت 🤝
گاهی وقتا لازمه یه آبجکت، رفرنس خودش رو به یه آبجکت یا متد دیگه بده.
public class Panda
{
public Panda Mate;
public void Marry(Panda partner)
{
Mate = partner;
// 'خودم' رو به عنوان جفتِ شریکم معرفی می‌کنم
partner.Mate = this;
}
}


قانون مهم ⚠️

this
فقط در اعضای غیر استاتیک (non-static) یک کلاس یا struct معتبره.

🔖 هشتگ‌ها:
#CSharp #Programming #Developer #DotNet #OOP #ThisKeyword
📖 سری آموزشی کتاب C# 12 in a Nutshell

خداحافظی با کدهای تکراری: معرفی Primary Constructors در 12 #C
از نوشتن این همه کد تکراری تو سازنده‌ها خسته شدید؟
public MyClass(string name) { this.name = name; }

این الگو که توش فقط پارامترهای ورودی به فیلدها اختصاص داده میشن، خیلی رایجه. خبر خوب اینه که از 12 #C، با Primary Constructors (سازنده‌های اصلی) می‌تونیم این کار رو خیلی شیک و کوتاه انجام بدیم!

1️⃣ Primary Constructor چیست و چطور کار می‌کند؟

این یه سینتکس جدیده که به شما اجازه میده پارامترهای سازنده اصلی رو مستقیماً بعد از اسم کلاس و داخل پرانتز تعریف کنید. کامپایلر به صورت خودکار یک سازنده بر اساس این پارامترها می‌سازه.

روش قدیمی: 👎
class Person
{
string firstName, lastName; // تعریف فیلدها
public Person(string firstName, string lastName) // تعریف سازنده
{
this.firstName = firstName; // اختصاص به فیلدها
this.lastName = lastName;
}
public void Print() => Console.WriteLine(firstName + " " + lastName);
}

روش مدرن با Primary Constructor: 👍
class Person(string firstName, string lastName)
{
public void Print() => Console.WriteLine(firstName + " " + lastName);
}
// استفاده ازش هم مثل قبل سادست
Person p = new Person("Alice", "Jones");
p.Print(); // Alice Jones


2️⃣ قوانین و نکات کلیدی ⚖️

پارامترها در کل کلاس قابل دسترسن: برخلاف سازنده معمولی که پارامترهاش فقط داخل همون بلوک زنده هستن، پارامترهای Primary Constructor در تمام بدنه کلاس قابل دسترسی هستن.

• سازنده اصلی: اگه سازنده‌های دیگه‌ای تو کلاس داشته باشید، باید با : this(...) سازنده اصلی (Primary) رو صدا بزنن.

• حذف سازنده پیش‌فرض: با تعریف سازنده اصلی، دیگه سازنده پیش‌فرض بدون پارامتر به صورت خودکار ساخته نمیشه.

3️⃣ کلاس با Primary Constructor در برابر record 🆚

رکوردها هم Primary Constructor دارن، ولی با یه تفاوت بزرگ: کامپایلر برای رکوردها، به صورت پیش‌فرض برای هر پارامتر، یه پراپرتی public init-only هم میسازه.

اما برای classها این اتفاق نمیفته و پارامترها به صورت private باقی می‌مونن (مگر اینکه خودتون به صورت دستی یک پراپرتی عمومی براشون بسازید).

4️⃣ محدودیت‌ها: کی ازش استفاده نکنیم؟ ⚠️

این قابلیت برای سناریوهای ساده عالیه، ولی محدودیت‌هایی هم داره: شما نمی‌تونید منطق اضافه‌ای (مثل اعتبارسنجی) رو مستقیم به خود سازنده اصلی اضافه کنید و برای این کارها باید از سازنده‌های سنتی استفاده کنید.

🔖 هشتگ‌ها:
#CSharp #DotNet #CSharp12 #Developer #OOP #CleanCode
📖 سری آموزشی کتاب C# 12 in a Nutshell
🚀 تکنیک‌های حرفه‌ای با Primary Constructors در 12 #C

تو پست قبلی با سینتکس ساده و جذاب Primary Constructors آشنا شدیم. اما قدرت واقعی این قابلیت، در تکنیک‌های پیشرفته‌تریه که به شما اجازه میده کدهای خیلی تمیزتر و هوشمندتری بنویسید.

امروز می‌خوایم با این ترفندها و البته محدودیت‌هاشون آشنا بشیم.

1️⃣ مقداردهی مستقیم فیلدها و پراپرتی‌ها
شما می‌تونید پارامترهای سازنده اصلی رو مستقیماً برای مقداردهی اولیه فیلدها و پراپرتی‌های عمومی استفاده کنید. این کار نیاز به نوشتن کد انتساب تکراری در یک سازنده سنتی رو حذف می‌کنه.
class Person(string firstName, string lastName)
{
// پارامتر firstName مستقیماً به فیلد عمومی FirstName اختصاص داده میشه
public readonly string FirstName = firstName;
// پارامتر lastName مستقیماً به پراپرتی عمومی LastName اختصاص داده میشه
public string LastName { get; } = lastName;
}


2️⃣ ماسک کردن (Masking) و تغییرناپذیری
یه تکنیک جالب، تعریف یه فیلد readonly با همون اسم پارامتره. در این حالت، فیلد، پارامتر اصلی رو "ماسک" می‌کنه. این کار یه راه ساده برای اطمینان از اینه که مقدار اولیه، بعد از ساخت آبجکت دیگه تغییر نمی‌کنه و به صورت داخلی readonly باقی می‌مونه.
class Person(string firstName, string lastName)
{
// این فیلدها، پارامترهای ورودی رو ماسک می‌کنن
readonly string firstName = firstName;
readonly string lastName = lastName.ToUpper(); // حتی می‌تونیم روشون عملیات هم انجام بدیم!
public void Print() => Console.WriteLine(firstName + " " + lastName);
}


3️⃣ اعتبارسنجی (Validation) در لحظه تولد! 🛡
قدرت اصلی اینجاست! شما می‌تونید منطق اعتبارسنجی رو مستقیماً در مقداردهی اولیه فیلدها پیاده کنید. با استفاده از "throw expressions"، می‌تونیم کد خیلی تمیزی برای چک کردن null یا مقادیر نامعتبر بنویسیم.
class Person(string firstName, string lastName)
{
// اگه lastName نال باشه، همینجا یه Exception پرتاب میشه
readonly string lastName = lastName ?? throw new ArgumentNullException(nameof(lastName));
public void Print() => Console.WriteLine(firstName + " " + lastName);
}

// new Person("Alice", null); // throws ArgumentNullException


4️⃣ محدودیت مهم: پراپرتی‌های خواندنی/نوشتنی ⚠️
با تمام این قدرت، Primary Constructors یه محدودیت مهم دارن. اگه بخواید یه پراپرتی خواندنی/نوشتنی ({ get; set; }) با منطق اعتبارسنجی داشته باشید، کار پیچیده میشه. چون باید اون منطق رو هم در مقداردهی اولیه و هم در اکسسور set تکرار کنید.

در این سناریو، برگشتن به روش سازنده سنتی و صریح معمولاً راه حل تمیزتریه.

🤔 حرف حساب و تجربه شما

Primary Constructors
یه ابزار عالی برای سناریوهای ساده و کلاس‌های تغییرناپذیره، ولی مثل هر ابزار دیگه‌ای، باید بدونیم کجا ازش استفاده کنیم و محدودیت‌هاش رو بشناسیم.

🔖 هشتگ‌ها:
#CSharp #DotNet #CSharp12 #Programming #Developer #OOP
Forwarded from Brain bytes
### E) Event-Driven Paradigm
Flow controlled by events rather than sequential commands.

public class Button
{
public event Action? Click;
public void OnClick() => Click?.Invoke();
}

var button = new Button();
button.Click += () => Console.WriteLine("Button clicked!");
button.OnClick();


Used in UI, messaging systems, reactive pipelines.

---

### F) Asynchronous Paradigm
Handle I/O or long-running tasks without blocking threads.

public async Task<string> FetchAsync()
{
using var http = new HttpClient();
return await http.GetStringAsync("https://example.com");
}

var data = await FetchAsync();
Console.WriteLine(data);


Combines async/await with Task for clearer concurrency.

---

### G) Reactive (Optional Extension)
Treat data as streams (e.g. with IObservable): react declaratively to change over time.

---

## 4) How C# Programming Model Enables These Paradigms

| Paradigm | Model Elements (C#) |
|---------------|---------------------|
| Imperative | loops, mutable locals, branching (if, switch) |
| OOP | class, interface, abstract, virtual, override, access modifiers |
| Functional | lambdas, delegates (Func<>, Action), LINQ, record types |
| Declarative | LINQ query syntax, attributes, expression trees |
| Event-Driven | event, delegates, EventHandler, UI frameworks |
| Asynchronous | async, await, Task, CancellationToken, ValueTask |
| Reactive | observables (via libraries), continuation chains |

C# is multi-paradigm: mix domain modeling (OOP) + data transformations (functional/declarative) + async I/O + events.

---

## 5) Choosing a Paradigm (Quick Guide)

| Situation | Best Fit |
|-----------|----------|
| Rich domain entities, lifecycle | OOP |
| Data querying/filtering | Declarative (LINQ) |
| Composable transformations, testability | Functional style |
| UI interactions, user input | Event-Driven |
| Network / file / database latency | Asynchronous |
| Simple scripts / procedural tasks | Imperative |
| Live data streams / continuous updates | Reactive |

Often you combine several in one solution.

---

## 6) Summary
Paradigm = How you think and structure the solution conceptually.
Programming Model = The language/runtime mechanisms enabling those structures.
C# provides a unified model supporting multiple paradigms seamlessly.

---

## 7) Glossary (English Term + Persian Meaning)

| Term | Persian |
|------|--------|
| Programming Paradigm | پارادایم برنامه‌نویسی / سبک مفهومی |
| Programming Model | مدل برنامه‌نویسی / مکانیزم اجرایی |
| Imperative | دستوری |
| Declarative | اعلامی / деклараتی |
| Object-Oriented (OOP) | شیءگرا |
| Encapsulation | کپسوله‌سازی |
| Inheritance | ارث‌بری |
| Polymorphism | چندریختی |
| Abstraction | انتزاع |
| Class | کلاس |
| Object | شیء |
| Method | متد |
| State | حالت |
| Functional Programming | برنامه‌نویسی تابعی |
| Pure Function | تابع خالص |
| Side Effect | عارضهٔ جانبی |
| Immutability | تغییرناپذیری |
| Lambda Expression | عبارت لامبدا |
| Delegate | نماینده (تابع اشاره‌ای) |
| LINQ | چارچوب کوئری یکپارچه |
| Query Syntax | نحوهٔ نگارش کوئری |
| Expression Tree | درخت بیان |
| Event | رویداد |
| Event-Driven | رویدادمحور |
| Asynchronous / Async | ناهمگام |
| Concurrency | همزمانی |
| Task | وظیفهٔ ناهمگام |
| CancellationToken | توکن لغو |
| Record | رکورد (نوع دادهٔ مختصر) |
| Virtual | مجازی (قابل بازنویسی) |
| Override | بازنویسی |
| Abstract | انتزاعی |
| Interface | اینترفیس / قرارداد |
| Reactive | واکنشی |
| Multi-Paradigm | چندپارادایمی |
| API | رابط برنامه‌نویسی کاربردی |
| Design Pattern | الگوی طراحی |
| Refactoring | بازآرایی کد |
| Maintainability | نگهداشت‌پذیری |
| Scalability | مقیاس‌پذیری |
| Deferred Execution | اجرای مؤخر |
| DSL | زبان دامنه‌محور |
| Idempotent | ایدمپوتنت (تکرار بدون تغییر نتیجه) |

---

## 8) Tags
#programming #paradigm #programming_model #CSharp #OOP #Functional #Declarative #LINQ #Async #EventDriven #Reactive #DotNet #SoftwareDesign #CleanCode #BrainBytes #Architecture #Coding #Developer