C# Geeks (.NET) – Telegram
چگونه امروز این مشکل را حل می‌کنم ⚡️🖥

امروز، همچنان با همان دکمه UI شروع می‌کنم. کاربر روی «Generate Report» کلیک می‌کند، اما به جای انتظار، backend درخواست را می‌پذیرد، آن را جایی ذخیره می‌کند (مثلاً به عنوان یک رکورد job در دیتابیس) و بلافاصله پاسخ می‌دهد. این جوهره‌ی ساخت asynchronous APIs است. سپس job توسط یک background worker پردازش می‌شود.

این worker می‌تواند یک hosted service، یک Quartz job، یا حتی یک AWS Lambda Function فعال‌شده توسط پیام صف (queue message) باشد. این وظیفه را انجام می‌دهد: داده‌ها را جمع‌آوری می‌کند، فایل را می‌سازد و آن را در فضایی مثل S3 یا Azure Blob آپلود می‌کند. 📂☁️

زمانی که گزارش آماده شد، worker وضعیت job را به «completed» به‌روزرسانی می‌کند و به کاربر اطلاع می‌دهد. این می‌تواند یک ایمیل با لینک دانلود یا پیام real-time SignalR باشد که در برنامه نمایش داده می‌شود. لینک به فایل ذخیره‌شده اشاره دارد و از طریق backend به صورت امن ارائه می‌شود.

مزیت این روش 🌟

اکنون کاربر منتظر یک HTTP request طولانی نیست. سرور connections را برای دقیقه‌ها باز نگه نمی‌دارد. اگر چیزی خراب شد، می‌توان آن را به صورت خودکار retry کرد. همچنین امکان ردیابی پیشرفت یا لغو job وجود دارد. اگر صد کاربر به طور همزمان درخواست گزارش بدهند، سیستم بدون قفل شدن scale می‌شود.

تجربه برای کاربر سریع‌تر به نظر می‌رسد، حتی اگر زمان واقعی تولید گزارش تغییر نکرده باشد. زیرا در نهایت، کاربران به performance metrics اهمیت نمی‌دهند، بلکه responsiveness برایشان مهم است. ⚡️

چرا هنوز از این سوال استفاده می‌کنم 🧐

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

برخی کاندیداها مستقیم به بهینه‌سازی کد و queries می‌روند، دقیقاً مثل من در گذشته. این نشان می‌دهد که آن‌ها با performance tuning آشنا هستند. سپس می‌توانم به سوالات فنی پیشرفته درباره algorithms، data structures یا database optimization بپردازم.

برخی لحظه‌ای مکث می‌کنند و درباره تجربه کاربر، پردازش background و fault tolerance فکر می‌کنند. اینجاست که گفتگوی واقعی شروع می‌شود: queues، retries، اطلاع‌رسانی، اشتراک امن فایل و غیره. این سناریو می‌تواند به بحث‌های گسترده‌تری درباره system design منجر شود.

هیچ پاسخ واحدی درست نیست. اما تفاوت بزرگی بین کسی که فقط روی کد تمرکز می‌کند و کسی که می‌تواند یک سیستم scalable طراحی کند وجود دارد.

درس مهم 🎓

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

بهینه‌سازی یک query یا حلقه می‌تواند کمک کند، اما مشکل انتظار، خطاها یا مقیاس‌پذیری را حل نمی‌کند. اگر کاربران زیادی همزمان همان گزارش را شروع کنند، طراحی synchronous به سرعت شکست می‌خورد. جریان asynchronous سیستم را پاسخگو و مقاوم نگه می‌دارد، بدون توجه به بار کاری.

این تغییر از بهینه‌سازی توابع به طراحی سیستم‌های scalable تفاوت بین یک توسعه‌دهنده خوب و یک توسعه‌دهنده عالی است. 🏆

امیدوارم مفید بوده باشد.🤍
🧩 چالش برنامه‌نویسی امروز — خروجی چی میشه؟

What will be the output?

A) C
B
B

B) B
B
B

C) A
B
B

C) B
B
D

<Link>
👆🏻
Anonymous Quiz
16%
"A"
27%
"B"
32%
"C"
24%
"D"
🌐 مدل TCP/IP

مدل TCP/IP یک چارچوب (framework) است که برای مدل‌سازی ارتباطات در شبکه استفاده می‌شود. این مدل در اصل مجموعه‌ای از پروتکل‌های شبکه است که در لایه‌های مختلف سازمان‌دهی شده‌اند تا نحوه‌ی ارتباطات در شبکه را مدل کنند.

این مدل شامل چهار لایه است:
🔹 Application
🔹 Transport
🔹 Network/Internet
🔹 Network Access

در حالی که مدل OSI دارای هفت لایه است، مدل چهار لایه‌ای TCP/IP ساده‌تر بوده و امروزه در اینترنت و سیستم‌های شبکه‌ای به‌طور گسترده استفاده می‌شود.

🎯 نقش TCP/IP

یکی از اهداف اصلی TCP/IP این است که اطمینان حاصل کند داده‌ای که از سمت فرستنده ارسال می‌شود، به‌صورت صحیح و کامل به گیرنده می‌رسد.

برای انجام این کار، داده قبل از ارسال به بخش‌های کوچک‌تری به نام Packet تقسیم می‌شود. هر Packet به‌صورت جداگانه در شبکه سفر می‌کند و زمانی که به مقصد رسید، دوباره به ترتیب درست بازسازی (Reassemble) می‌شود.

🧩 نکته: این فرآیند باعث می‌شود احتمال خطا کاهش یابد و پیام نهایی به‌طور کامل و دقیق به مقصد برسد.
🧱 لایه‌های مدل TCP/IP


1️⃣ Application Layer

بالاترین لایه در مدل TCP/IP است و نزدیک‌ترین لایه به کاربر محسوب می‌شود.

در این لایه، تمام برنامه‌هایی که ما استفاده می‌کنیم — مثل مرورگر وب، کلاینت ایمیل یا ابزارهای اشتراک فایل — به شبکه متصل می‌شوند.

این لایه مثل یک پل ارتباطی بین نرم‌افزارهای کاربر (مثل Chrome، Gmail یا WhatsApp) و لایه‌های پایین‌تر شبکه عمل می‌کند که واقعاً داده‌ها را ارسال و دریافت می‌کنند.

این لایه از پروتکل‌های مختلفی پشتیبانی می‌کند مانند:
HTTP برای وب‌سایت‌ها 🌍
FTP برای انتقال فایل‌ها 📁
SMTP برای ارسال ایمیل‌ها ✉️
DNS برای یافتن آدرس وب‌سایت‌ها 🌐

همچنین وظایفی مانند قالب‌بندی داده‌ها (Data Formatting)، رمزنگاری (Encryption) برای حفظ امنیت داده‌ها، و مدیریت نشست‌ها (Session Management) برای کنترل ارتباطات فعال را بر عهده دارد.

⚙️ 2️⃣ Transport Layer

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

این لایه از دو پروتکل اصلی استفاده می‌کند: TCP و UDP — بسته به اینکه ارتباط نیاز به قابلیت اطمینان (Reliability) داشته باشد یا سرعت.

🔹️TCP (Transmission Control Protocol)
زمانی استفاده می‌شود که داده باید دقیق و کامل باشد؛ مانند زمانی که در حال بارگذاری یک صفحه‌ی وب یا دانلود یک فایل هستیم.
خطاها را بررسی می‌کند، بخش‌های گم‌شده را دوباره ارسال می‌کند و ترتیب داده‌ها را حفظ می‌نماید.

🔹️UDP (User Datagram Protocol)
سریع‌تر است اما تحویل داده را تضمین نمی‌کند.
این ویژگی باعث می‌شود برای مواردی مثل پخش زنده‌ی ویدیو یا بازی‌های آنلاین که سرعت مهم‌تر از دقت صددرصدی است، مناسب باشد.

🌍 3️⃣ Internet Layer

وظیفه دارد بهترین مسیر را برای انتقال داده‌ها در میان شبکه‌های مختلف پیدا کند تا داده بتواند به مقصد درست برسد.
این لایه مانند یک کنترل‌کننده‌ی ترافیک شبکه عمل می‌کند و کمک می‌کند Packetها از یک شبکه به شبکه‌ی دیگر حرکت کنند تا به دستگاه مورد نظر برسند.

این لایه از Internet Protocol (IP) برای اختصاص آدرس منحصربه‌فرد (IP Address) به هر دستگاه استفاده می‌کند تا مشخص شود داده باید به کجا ارسال شود.

وظیفه‌ی اصلی این لایه مسیر‌یابی (Routing) است؛ یعنی تصمیم‌گیری درباره‌ی بهترین مسیر برای حرکت داده‌ها.
همچنین کارهایی مانند Packet Forwarding (انتقال داده از یک نقطه به نقطه‌ی دیگر)، Fragmentation (شکستن داده‌های بزرگ به بخش‌های کوچک‌تر) و Addressing را نیز انجام می‌دهد.

📡 4️⃣ Network Access Layer

پایین‌ترین لایه در مدل TCP/IP است. این لایه با اتصال فیزیکی واقعی بین دستگاه‌های موجود در یک شبکه‌ی محلی (LAN) سر و کار دارد — مثل کامپیوترهایی که از طریق کابل یا Wi-Fi به هم متصل هستند.

این لایه اطمینان حاصل می‌کند که داده بتواند از طریق سخت‌افزارهایی مانند سیم‌ها، سوئیچ‌ها یا سیگنال‌های بی‌سیم منتقل شود.
همچنین وظایف مهمی بر عهده دارد مانند:

• استفاده از MAC Address برای شناسایی دستگاه‌ها 🖥
• ایجاد Frameها (قالب داده برای انتقال در لینک فیزیکی)
• بررسی خطاهای ابتدایی در هنگام ارسال داده
⚙️ نحوهٔ کار مدل TCP/IP

📤 زمانی که داده ارسال می‌شود (از Sender به Receiver)

Application Layer 🧩:

داده‌های کاربر را با استفاده از پروتکل‌هایی مانند HTTP، FTP یا SMTP آماده می‌کند.

Transport Layer (TCP/UDP) 🚦:

داده را به بخش‌های کوچک‌تر (Segments) تقسیم کرده و اطمینان حاصل می‌کند که انتقال یا قابل اعتماد (TCP) باشد یا سریع‌تر (UDP).

Internet Layer (IP) 🌍:

آدرس‌های IP را اضافه می‌کند و بهترین مسیر را برای هر Packet انتخاب می‌کند.

Link Layer (Network Access Layer) 🔗:

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

📥 زمانی که داده دریافت می‌شود (در مقصد)

Link Layer ⚡️:

بیت‌ها را از شبکه دریافت کرده و Frameها را بازسازی می‌کند تا به لایه‌ی بعدی منتقل شوند.

Internet Layer 🌐:

آدرس IP را بررسی کرده، IP Header را حذف می‌کند و داده را به لایه‌ی Transport می‌فرستد.

Transport Layer 📦:
Segments

را دوباره ترکیب می‌کند، خطاها را بررسی کرده و از کامل بودن داده مطمئن می‌شود.

Application Layer 🖥:

داده‌ی نهایی را به اپلیکیشن مناسب تحویل می‌دهد (برای مثال، نمایش یک صفحه وب در مرورگر).

💡 مقایسه TCP/IP و OSI — چرا TCP/IP پرکاربردتر است؟

مدل TCP/IP نسبت به OSI ساده‌تر، عملی‌تر و برای شبکه‌های واقعی و اینترنت بسیار رایج‌تر است.

🧠 دلیل | 💬 توضیح
━━━━━━━━━━━━━━━
⚙️ ساختار ساده‌تر (Simpler Structure)

🔹 فقط ۴ لایه دارد (در مقابل ۷ لایه در OSI)، بنابراین پیاده‌سازی و درک آن در سیستم‌های واقعی بسیار ساده‌تر است.

🧩 طراحی مبتنی بر پروتکل (Protocol-Driven Design)

🔹 مدل TCP/IP بر اساس پروتکل‌های واقعی ساخته شده است، در حالی که مدل OSI بیشتر یک چارچوب نظری و آموزشی است.

🚀 انعطاف‌پذیری و مقاومت بالا (Flexibility & Robustness)

🔹 به‌خوبی با سخت‌افزارها و شبکه‌های مختلف سازگار می‌شود و قابلیت‌هایی مانند Error Handling, Routing و Congestion Control را پشتیبانی می‌کند.

🌍 استاندارد باز (Open Standard)

🔹 یک استاندارد آزاد و عمومی است که توسط هیچ سازمان خاصی کنترل نمی‌شود و به همین دلیل در سراسر جهان پذیرفته شده است.

🧱 کاربرد واقعی در مقابل مدل مفهومی (Actual Use vs Conceptual Model)

🔹 مدل OSI برای آموزش مفید است، اما در دنیای واقعی، این TCP/IP است که واقعاً در شبکه‌ها به‌کار می‌رود.
🌐 Advantages of TCP/IP Model (مزایای مدل TCP/IP)


Interoperability (قابلیت همکاری):
مدل TCP/IP به سیستم‌ها و شبکه‌های مختلف اجازه می‌دهد با هم ارتباط برقرار کنند، و باعث افزایش سازگاری و همکاری بین پلتفرم‌های متنوع می‌شود.

Scalability (مقیاس‌پذیری):
این مدل بسیار مقیاس‌پذیر است و هم برای شبکه‌های کوچک (LAN) و هم شبکه‌های بزرگ مانند اینترنت (WAN) مناسب است.

Standardization (استانداردسازی):
بر اساس استانداردهای باز ساخته شده است؛ بنابراین دستگاه‌ها و نرم‌افزارهای مختلف می‌توانند بدون مشکل ناسازگاری با هم کار کنند.

Flexibility (انعطاف‌پذیری):
از انواع مختلف پروتکل‌های مسیریابی، نوع داده‌ها و روش‌های ارتباطی پشتیبانی می‌کند و به همین دلیل برای نیازهای متنوع شبکه قابل تطبیق است.

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

⚠️ Disadvantages of TCP/IP Model (معایب مدل TCP/IP)


Security Concerns (مسائل امنیتی):
TCP/IP
در ابتدا با تمرکز بر امنیت طراحی نشده بود. پروتکل‌هایی مانند SSL/TLS بعداً برای افزایش امنیت اضافه شدند، اما این موضوع باعث ایجاد برخی آسیب‌پذیری‌ها در ساختار پایه شده است.

Inefficiency for Small Networks (ناکارآمدی برای شبکه‌های کوچک):
در شبکه‌های کوچک، پیچیدگی و سربار (Overhead) این مدل ممکن است غیرضروری و ناکارآمد باشد.

Limited by Address Space (محدودیت در فضای آدرس‌دهی):
نسخه قدیمی IPv4 فضای آدرس محدودی دارد که می‌تواند باعث کمبود آدرس‌ها در شبکه‌های بزرگ شود (هرچند IPv6 این مشکل را برطرف کرده است).

Data Overhead (سربار داده):
پروتکل TCP مقدار زیادی سربار کنترلی برای اطمینان از ارسال صحیح داده‌ها دارد که ممکن است بر عملکرد و سرعت تأثیر بگذارد.

📘 در مجموع، مدل TCP/IP ترکیبی از سادگی، پایداری و سازگاری جهانی است که باعث شده ستون فقرات ارتباطات اینترنت امروزی باشد. 🌍

🔖هشتگ‌ها:
#Networking #TCPIP #ComputerNetworks #InternetProtocols
چطور یک برنامه‌نویس بهتر بشم؟ 💻

مثل هر چیزی که درش خوب نیستیم،
باید تمرین کنیم! 💪
برنامه‌نویسی هم از این قاعده مستثنی نیست!

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

چند مثال بامزه برای روشن‌تر شدن: 😄


نمی‌تونم فقط با دیدن ۲۰۰ تا ویدیوی بسکتبال، توی بسکتبال خوب بشم. 🏀

نمی‌تونم فقط با خوندن درباره‌ی بدنسازی، اتصال ذهن و عضله‌ی قوی پیدا کنم. 🏋️

نمی‌تونم ۱۰۰ تا آموزش رقص ببینم و انتظار داشته باشم همون اول عالی برقصم. 💃

پس باید دست به کار بشیم و تکرار کنیم تا بهتر بشیم.
این پایه‌ی اصلی پیشرفته.
البته می‌تونیم تمرین رو با چیزهای دیگه هم تقویت کنیم مثل:

📚 کتاب‌ها
📰 مقاله‌ها
🎥 ویدیوها
🎓 دوره‌ها

اما در نهایت باید چیزی بسازی.
همیشه به بقیه می‌گم بسازن!
شاید بگی: «خیلی سخته، من نمی‌تونم همچین چیزی بسازم!»

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

از همون قسمت شروع کن، سعی کن بسازیش.
وقتی گیر کردی، از مقاله‌ها و ویدیوها کمک بگیر.
بعدش قسمت بعدی رو بساز.
و همین کار رو تکرار کن. 🔁

مهم نیست چی داری می‌سازی،
تا وقتی که داری لذت می‌بری و یاد می‌گیری، در مسیر درستی هستی.

با گذشت زمان، مهارت حل مسئله، تفکر انتقادی و درک مفاهیم کلی‌ات قوی‌تر می‌شه.
زبان برنامه‌نویسی برات مثل حافظه‌ی عضلانی می‌شه، چون واقعاً داری ازش استفاده می‌کنی. 💪

بعد می‌تونی به سراغ زبان‌ها و تکنولوژی‌های دیگه بری
و همه‌ی اون مفاهیم پایه‌ای که یاد گرفتی رو با خودت ببری. 🚀

پس اگه هنوز «خوب» نیستی، نگران نباش.
تمرین کن، زمان بده، و اگر عاشق این کاری،
هیچ‌وقت تسلیم نشو. ❤️🔥
Role-Based Access Control🛡
🛡 ساخت APIهای امن با Role-Based Access Control در ASP.NET Core

🔐 در Authentication به شما می‌گوید کاربر کیست،
اما Authorization به شما می‌گوید کاربر چه کاری می‌تواند انجام دهد.
بیشتر توسعه‌دهندگان NET. در ابتدا با بررسی‌های ساده‌ی نقش (Role-Based Checks) شروع می‌کنند:
«آیا این کاربر Admin است؟» 👀
اما وقتی برنامه رشد می‌کند، خیلی زود متوجه می‌شوید که فقط نقش‌ها کافی نیستند.
به مجوزهای جزئی‌تر (Granular Permissions) نیاز دارید که بتوان آن‌ها را به‌صورت انعطاف‌پذیر ترکیب و تخصیص داد.
اینجاست که Role-Based Access Control (RBAC) می‌درخشد.
به‌جای اینکه در همه‌جا در کد نقش‌ها را چک کنید، شما مجوزهای خاص (Permissions) را تعریف می‌کنید
و نقش‌ها را طوری طراحی می‌کنید که آن مجوزها را حمل کنند.
ممکن است یک کاربر نقش Manager داشته باشد،
اما چیزی که اهمیت دارد این است که آیا او مجوز users:delete را دارد یا نه. 🧾
بیایید ببینیم چطور می‌توانیم یک سیستم احراز مجوز انعطاف‌پذیر و مبتنی بر مجوز در ASP.NET Core بسازیم. 🚀

🧩 درک اجزای اصلی RBAC

مدل RBAC از سه جزء کلیدی تشکیل شده است که با هم کار می‌کنند:
👤 Users → اختصاص داده می‌شوند به → 🧑‍💼 Roles → که شامل هستند از → 🔑 Permissions

🔄 جریان کار به این صورت است:

🔹️Users (کاربران):
افراد واقعی که از سیستم شما استفاده می‌کنند.
🔹️Roles (نقش‌ها):
گروهی از مجوزهای مرتبط (مثل Admin، Manager، Editor).
🔹️Permissions (مجوزها):
عملیات خاصی که کاربران می‌توانند انجام دهند
(مثل users:read، orders:create، reports:delete).

زیبایی RBAC در انعطاف‌پذیری آن است.
می‌توانید چندین نقش به یک کاربر اختصاص دهید
و نقش‌ها را بدون تغییر در تخصیص کاربران ویرایش کنید.
به همه‌ی Managerها می‌خواهید امکان export گزارش‌ها بدهید؟
فقط مجوز reports:export را به نقش Manager اضافه کنید
این روش بسیار قابل نگهداری‌تر است
تا اینکه بخواهید در کد بررسی کنید که آیا کسی Admin یا Super Manager است.
علاوه بر این، RBAC یک نقطه‌ی گسترش اضافی فراهم می‌کند:
می‌توانید برای برخی کاربران مجوزهای سفارشی ایجاد کنید
بدون اینکه نیاز به ساخت نقش‌های جدید باشد. 💡

⚙️ ساخت یک Authorization Handler سفارشی در ASP.NET Core

در سیستم احراز مجوز (Authorization) در ASP.NET Core، مفاهیم اصلی بر پایه‌ی Policy‌ها و Requirement‌ها ساخته می‌شوند.
در این بخش، می‌خواهیم یک Handler سفارشی بسازیم که مجوزها (Permissions) را از داخل Claims کاربر بررسی کند. 🔍

🧠 کد پیاده‌سازی Handler سفارشی
public class PermissionAuthorizationRequirement(params string[] allowedPermissions)
: AuthorizationHandler<PermissionAuthorizationRequirement>, IAuthorizationRequirement
{
public string[] AllowedPermissions { get; } = allowedPermissions;

protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
PermissionAuthorizationRequirement requirement)
{
foreach (var permission in requirement.AllowedPermissions)
{
bool found = context.User.FindFirst(c =>
c.Type == CustomClaimTypes.Permission &&
c.Value == permission) is not null;

if (found)
{
context.Succeed(requirement);
break;
}
}
return Task.CompletedTask;
}
}
🧩 در پشت صحنه چه اتفاقی می‌افتد؟

این کلاس در واقع هر دو نقش Requirement و Handler را با هم ترکیب کرده است —
یعنی هم مشخص می‌کند چه مجوزهایی لازم‌اند، و هم چگونه باید بررسی شوند.
این کار باعث می‌شود منطق مرتبط در یک جا نگهداری شود و از تکرار (Boilerplate) جلوگیری کند.
هندلر در میان Claims کاربر جست‌وجو می‌کند تا Claimی با نوع Permission پیدا کند
که مقدار آن با یکی از مجوزهای موردنیاز مطابقت داشته باشد.
این عمل به صورت OR است — یعنی اگر کاربر حتی یکی از مجوزهای خواسته‌شده را داشته باشد، اجازه‌ی دسترسی خواهد داشت

اگر Claim موردنظر یافت شود، با فراخوانی
context.Succeed(requirement)

به ASP.NET Core اطلاع می‌دهیم که شرط تأیید شده است، و دیگر نیازی به بررسی بقیه نیست.

در صورت نیاز، می‌توانید این رفتار را به AND تغییر دهید تا تمام مجوزها الزامی باشند 🔒

🏷 تعریف Claim Type سفارشی

برای شناسایی نوع مجوز در Claims، ابتدا باید نوع Claim خود را تعریف کنید:
public static class CustomClaimTypes
{
public const string Permission = "permission";
}


🪪 افزودن Claims هنگام صدور JWT Token

هنگام ساخت توکن JWT یا تنظیم Claims کاربر، می‌توانید مجوزها را از دیتابیس خوانده و در Claims اضافه کنید:
var permissions = await (
from role in dbContext.Roles
join permission in dbContext.RolePermissions on role.Id equals permission.RoleId
where roles.Contains(role.Name)
select permission.Name)
.Distinct()
.ToArrayAsync();

List<Claim> claims =
[
new(JwtRegisteredClaimNames.Sub, user.Id),
new(JwtRegisteredClaimNames.Email, user.Email!),
..roles.Select(r => new Claim(ClaimTypes.Role, r)),
..permissions.Select(p => new Claim(CustomClaimTypes.Permission, p))
];

var tokenDenoscriptor = new SecurityTokenDenoscriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.UtcNow.AddMinutes(configuration.GetValue<int>("Jwt:ExpirationInMinutes")),
SigningCredentials = credentials,
Issuer = configuration["Jwt:Issuer"],
Audience = configuration["Jwt:Audience"]
};

var tokenHandler = new JsonWebTokenHandler();

string accessToken = tokenHandler.CreateToken(tokenDenoscriptor);
ایجاد Clean APIها با استفاده از Extension Methodها در ASP.NET Core

کار با Authorization Policyهای خام درست است ولی معمولاً کد را طولانی و پیچیده می‌کند.
برای بهبود تجربهٔ توسعه‌دهنده، می‌توانیم از Extension Method‌ها استفاده کنیم تا کد خواناتر و تمیزتر شود. 🧩

🧠 ایجاد Extension Method برای مجوزها
public static class PermissionExtensions
{
public static void RequirePermission(
this AuthorizationPolicyBuilder builder,
params string[] allowedPermissions)
{
builder.AddRequirements(new PermissionAuthorizationRequirement(allowedPermissions));
}
}

🔹 با این متد، می‌توانید به‌صورت مستقیم و تمیز در Policyها از ()RequirePermission استفاده کنید.

⚡️ استفاده در Minimal APIها
public static class Permissions
{
public const string UsersRead = "users:read";
public const string UsersUpdate = "users:update";
public const string UsersDelete = "users:delete";
}

app.MapGet("me", async (ApplicationDbContext dbContext, ClaimsPrincipal User) =>
{
var user = await dbContext.Users
.AsNoTracking()
.Where(u => u.Id == int.Parse(User.FindFirstValue(JwtRegisteredClaimNames.Sub)!))
.Select(u => new UserDto
{
u.Id,
u.Email,
u.FirstName,
u.LastName
})
.SingleOrDefaultAsync();

return Results.Ok(user);
})
.RequireAuthorization(policy => policy.RequirePermission(Permissions.UsersRead));

💡 حالا endpointها تمیز، خوانا و کاملاً منطبق با الگوی Clean Architecture هستند.

🧩 استفاده در MVC Controllerها

برای MVC Controllerها می‌توانیم Attribute اختصاصی بسازیم تا کار با مجوزها ساده‌تر شود:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class RequirePermissionAttribute(params string[] permissions) : AuthorizeAttribute
{
public RequirePermissionAttribute(params string[] permissions)
: base(policy: string.Join(",", permissions))
{
}
}

🔧 سپس Policyها را در DI Container ثبت می‌کنیم:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("users:read", policy => policy.RequirePermission(Permissions.UsersRead))
.AddPolicy("users:update", policy => policy.RequirePermission(Permissions.UsersUpdate));

📦 حالا استفاده از آن در Controller بسیار تمیز و ساده است:
[RequirePermission(Permissions.UsersUpdate)]
public async Task<IActionResult> UpdateUser(int id, UpdateUserRequest request)
{
// Your logic here
}


🚀 Extension Points برای محیط Production

پیاده‌سازی بالا کاملاً کاربردی است، اما می‌توان آن را در محیط‌های Production گسترش داد.
دو نقطهٔ کلیدی برای توسعه وجود دارد:

🧱 Type-Safe Permissions با استفاده از Enum

به‌جای استفاده از رشته‌های جادویی (Magic Strings)، می‌توان از Enumها استفاده کرد تا از بررسی در زمان کامپایل (Compile-Time Safety) بهره ببریم:
public enum Permission
{
UsersRead,
UsersUpdate,
UsersDelete,
OrdersCreate,
ReportsExport
}

سپس هنگام صدور JWT Token یا بررسی مجوز،
باید Enum را به string تبدیل کنید و هنگام خواندن Claims مجدداً آن را به Enum برگردانید. 🔁

این کار باعث می‌شود اشتباهات تایپی و ناسازگاری‌های احتمالی حذف شوند،
و سیستم امن‌تر، خواناتر و مقیاس‌پذیرتر شود. 💪
Server-Side Permission Resolution در ASP.NET Core

در بسیاری از پروژه‌ها، توسعه‌دهندگان تمام Permissionها را درون JWT Token ذخیره می‌کنند.
اما این روش باعث افزایش حجم Token و کاهش امنیت می‌شود.
راه بهتر این است که مجوزها را در سمت سرور (Server-Side) واکشی کنیم. ⚙️

🧠 استفاده از IClaimsTransformation برای افزودن Permissionها در سمت سرور
public class PermissionClaimsTransformation(IPermissionService permissionService)
: IClaimsTransformation
{
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (principal.Identity?.IsAuthenticated != true)
{
return principal;
}

var userId = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (userId == null)
{
return principal;
}

// واکشی مجوزها از دیتابیس و سپس ذخیره در Cache
// نکته مهم: حتماً نتایج را کش کنید تا در هر درخواست کوئری تکراری به دیتابیس نرود
var permissions = await permissionService.GetUserPermissionsAsync(userId);

var claimsIdentity = (ClaimsIdentity)principal.Identity;
foreach (var permission in permissions)
{
claimsIdentity.AddClaim(new Claim(CustomClaimTypes.Permission, permission));
}

return principal;
}
}

📦 سپس این کلاس را در DI Container ثبت می‌کنیم:
builder.Services.AddScoped<IClaimsTransformation, PermissionClaimsTransformation>();

🔹 با این روش، JWT شما سبک و امن باقی می‌ماند،
در حالی که Authorization همچنان سریع و مبتنی بر Claims انجام می‌شود. ⚡️

🧩 جمع‌بندی (Takeaway)

الگوی RBAC (Role-Based Access Control)
فرآیند Authorization را از یک دردسر نگهداری به یک سیستم منعطف و مقیاس‌پذیر تبدیل می‌کند. 🚀

از Permissions شروع کنید، نه Roles
تعریف کنید کاربر چه عملیاتی می‌تواند انجام دهد، نه اینکه چه نقشی دارد.

Custom Authorization Handlerها
کنترل کامل روی نحوهٔ اعتبارسنجی مجوزها به شما می‌دهند.

Extension Methodها
کد را تمیز، منسجم و خوانا می‌کنند.

Type-Safe Enumها + Server-Side Permission Resolution
کد را پایدارتر، Tokenها را سبک‌تر و سیستم را قابل نگهداری‌تر می‌کنند.

نتیجه؟

یک سیستم Authorization تمیز، تست‌پذیر، و منعطف
که به‌سادگی با رشد برنامهٔ شما سازگار می‌شود. 💪

🔖هشتگ‌ها:
#ASPNetCore #RBAC #Authorization #DotNet #CleanArchitecture #CSharp
Forwarded from TondTech (مسعود بیگی)
اگر دنبال خلق ارزش با AI هستید مثل من و خیلی دیگه از بچه ها میتونید این کتاب رو دانلود کنید رایگان. یا نسخه چاپی شو با کمتر از یک پول پیتزا از ما بخرید

https://refhub.ir/fa/refrence_detail/ai-value-creators-beyond-the-generative-ai-user-mindset/

لایک و شیر و کامنت کنید برسه دست کسی که نیازش داره
💡 بهترین شیوه‌ها برای تست یکپارچه‌سازی با Testcontainers در NET.

تست‌های یکپارچه‌سازی با Testcontainers قدرتمند هستند، اما اگر از الگوهای صحیح پیروی نکنید، به سرعت می‌توانند به یک کابوس نگهداری تبدیل شوند. 😫

من تیم‌هایی را دیده‌ام که با تست‌های شکننده (flaky)، مجموعه تست‌های کند، و سردردهای پیکربندی دست و پنجه نرم می‌کنند که با رعایت شیوه‌های بهتر از همان ابتدا، قابل اجتناب بودند.

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

Testcontainers چگونه تست یکپارچه‌سازی را تغییر می‌دهد؟

تست‌های یکپارچه‌سازی سنتی اغلب به دیتابیس‌های تست اشتراکی یا جایگزین‌های درون-حافظه‌ای (in-memory) تکیه می‌کنند که با رفتار محیط پروداکشن مطابقت ندارند. شما یا با آلودگی تست بین اجراها سر و کار دارید یا واقع‌گرایی را فدای سرعت می‌کنید.

تست کانتینر‌ها این مشکل را با بالا آوردن کانتینرهای واقعی Docker 🐳 برای وابستگی‌های شما حل می‌کند. تست‌های شما در برابر PostgreSQL، Redis یا هر سرویس دیگری که در پروداکشن استفاده می‌کنید، اجرا می‌شوند. وقتی تست‌ها کامل شدند، کانتینرها از بین می‌روند و هر بار یک محیط تمیز در اختیار شما قرار می‌دهند.

این جادو 🪄 از طریق API داکر اتفاق می‌افتد. Testcontainers کل چرخه حیات را مدیریت می‌کند: دریافت ایمیج‌ها، شروع کانتینرها، انتظار برای آماده شدن، و پاک‌سازی. کد تست شما فقط باید بداند چگونه به آن‌ها متصل شود.

پیش‌نیازها 📦

اول، مطمئن شوید که پکیج‌های لازم را دارید:
Install-Package Microsoft.AspNetCore.Mvc.Testing
Install-Package Testcontainers.PostgreSql
Install-Package Testcontainers.Redis

ساختن کانتینرهای تست 🏗

در اینجا نحوه راه‌اندازی کانتینرهای خود با پیکربندی مناسب آمده است:
PostgreSqlContainer _postgresContainer = new PostgreSqlBuilder()
.WithImage("postgres:17")
.WithDatabase("devhabit")
.WithUsername("postgres")
.WithPassword("postgres")
.Build();

RedisContainer _redisContainer = new RedisBuilder()
.WithImage("redis:latest")
.Build();

برای شروع و توقف تمیز کانتینرها در سراسر مجموعه تست خود، IAsyncLifetime را در WebApplicationFactory خود پیاده‌سازی کنید:
public sealed class IntegrationTestWebAppFactory : WebApplicationFactory<Program>, IAsyncLifetime
{
// ... تعریف کانتینرها ...

public async Task InitializeAsync()
{
await _postgresContainer.StartAsync();
await _redisContainer.StartAsync();
// وابستگی‌های دیگر را اینجا شروع کنید
}

public async Task DisposeAsync()
{
await _postgresContainer.StopAsync();
await _redisContainer.StopAsync();
}
}

این کار تضمین می‌کند که کانتینرها قبل از اجرای تست‌ها آماده و پس از آن پاک‌سازی شوند. این یعنی هیچ وضعیت باقیمانده از داکر یا شرایط رقابتی (race conditions) وجود نخواهد داشت.

📌 نکته: نسخه‌های ایمیج خود را پین کنید (مانند postgres:17) تا از غافلگیری‌های ناشی از تغییرات بالادستی جلوگیری کنید.

انتقال پیکربندی به اپلیکیشن شما

بزرگترین اشتباهی که می‌بینم، هاردکد کردن connection stringها است. Testcontainers پورت‌های داینامیک اختصاص می‌دهد. هیچ چیز را هاردکد نکنید.

در عوض، مقادیر را از طریق WebApplicationFactory.ConfigureWebHost تزریق کنید:
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseSetting("ConnectionStrings:Database", _postgresContainer.GetConnectionString());
builder.UseSetting("ConnectionStrings:Redis", _redisContainer.GetConnectionString());
}


📍نکته کلیدی استفاده از متد UseSetting برای انتقال داینامیک connection stringها است. این کار همچنین از هرگونه شرایط رقابتی یا تداخل با تست‌های دیگری که ممکن است به صورت موازی اجرا شوند، جلوگیری می‌کند.

اشتراک‌گذاری تنظیمات پرهزینه با xUnit Collection Fixtures
💡فیکسچر تست (test fixture) چیست؟

یک فیکسچر یک زمینه اشتراکی برای تست‌های شماست که به شما اجازه می‌دهد منابع پرهزینه مانند دیتابیس‌ها یا message brokerها را یک بار راه‌اندازی کرده و در چندین تست از آن‌ها استفاده مجدد کنید.

اینجاست که اکثر تیم‌ها دچار مشکل می‌شوند. انتخاب بین class و collection fixtures بر عملکرد و ایزوله‌سازی تست تأثیر می‌گذارد.
Class Fixture 🏠 :
یک کانتینر برای هر کلاس تست:

زمانی استفاده کنید که تست‌ها وضعیت سراسری را تغییر می‌دهند یا دیباگ کردن تعاملات تست دشوار می‌شود.
public class AddItemToCartTests : IClassFixture<DevHabitWebAppFactory>
{
// ...
}


Collection Fixture 🏢 :
یک کانتینر مشترک بین چندین کلاس تست:

زمانی استفاده کنید که تست‌های شما وضعیت اشتراکی را تغییر نمی‌دهند یا می‌توانید به طور قابل اعتماد بین تست‌ها پاک‌سازی انجام دهید.
[CollectionDefinition(nameof(IntegrationTestCollection))]
public sealed class IntegrationTestCollection : ICollectionFixture<DevHabitWebAppFactory> {}

// سپس آن را به کلاس‌های تست خود اعمال کنید:
[Collection(nameof(IntegrationTestCollection))]
public class AddItemToCartTests : IntegrationTestFixture
{
// ...
}


چه زمانی از کدام استفاده کنیم:🤔

🔹️Class fixtures
وقتی به ایزوله‌سازی کامل بین کلاس‌های تست نیاز دارید (کندتر اما امن‌تر).

🔹️Collection fixtures
وقتی کلاس‌های تست با یکدیگر تداخل ندارند (سریع‌تر اما نیازمند نظم).

نوشتن تست‌های یکپارچه‌سازی قابل نگهداری ✍️
با پیکربندی صحیح زیرساخت، تست‌های واقعی شما باید روی منطق بیزینس تمرکز کنند:
[Fact]
public async Task Should_ReturnFailure_WhenNotEnoughQuantity()
{
//Arrange
Guid customerId = await Sender.CreateCustomerAsync(Guid.NewGuid());
// ...

//Act
Result result = await Sender.Send(command);

//Assert
result.Error.Should().Be(TicketTypeErrors.NotEnoughQuantity(Quantity));
}

توجه کنید که چگونه تست‌ها به جای دغدغه‌های زیرساختی، روی قوانین بیزینس تمرکز دارند. شما PostgreSQL یا Redis را mock نمی‌کنید، شما رفتار واقعی را تست می‌کنید.

نتیجه‌گیری 👍
تست کانتینر‌ها تست یکپارچه‌سازی را با دادن اطمینانی که از تست در برابر وابستگی‌های واقعی حاصل می‌شود، متحول می‌کند.

ساده شروع کنید: یک تست یکپارچه‌سازی را که در حال حاضر از mockها یا دیتابیس‌های درون-حافظه‌ای استفاده می‌کند، انتخاب کرده و آن را برای استفاده از Testcontainers تبدیل کنید. بلافاصله تفاوت در اطمینان را هنگامی که آن تست پاس می‌شود، متوجه خواهید شد.
"افرادتان را در اولویت قرار دهید و به آنها کمک کنید تا بهترین کار ممکن را انجام دهند."
Forwarded from Brain bytes
🧠 Brain bytes
Channel: t.me/brain_bytes

# Programming Paradigms vs Programming Model

## 1) What Is a Programming Paradigm?
A programming paradigm is a conceptual style or philosophy for thinking about problems and structuring solutions in code.
It answers questions like:
- How do we view data? (objects, pure values, sequences, events)
- How do we express behavior? (methods, functions, queries, handlers)
- How do system parts interact? (method calls, message passing, events, streams)

Paradigms guide how you mentally model the domain. They are about “How should I think and organize?” not about specific syntax.
Examples: Imperative, Object-Oriented (OOP), Functional, Declarative, Event-Driven, Asynchronous, Reactive.

## 2) What Is a Programming Model?
A programming model is the concrete set of language mechanisms, runtime behavior, keywords, and APIs that let you implement one or more paradigms.
In C#, the programming model provides:
- OOP constructs: class, interface, abstract, virtual, override
- Functional/declarative tools: LINQ (Where, Select, query syntax), lambdas, delegates (Func<>, Action), expression trees, record types
- Asynchronous constructs: async, await, Task, ValueTask, CancellationToken
- Event-driven features: event, EventHandler, delegates
- Memory/execution semantics: managed runtime, garbage collection, value vs reference types

In short:
Paradigm = conceptual lens (thinking model)
Programming model = toolbox + mechanics enabling that lens

---

## 3) Major Paradigms with C# Examples

### A) Imperative Paradigm
Focus: Explicit step-by-step instructions and mutable state.

int sum = 0;
int[] numbers = { 3, 5, 7, 9 };
for (int i = 0; i < numbers.Length; i++)
{
sum += numbers[i];
}
Console.WriteLine(sum);


Characteristics: loops, assignments, control flow (if, for, while).

---

### B) Object-Oriented Programming (OOP)
Model the world as objects combining state + behavior.

public class Car
{
public string Brand { get; }
public int Speed { get; private set; }

public Car(string brand, int speed)
{
Brand = brand;
Speed = speed;
}

public void Accelerate(int amount) => Speed += amount;
public override string ToString() => $"{Brand} => {Speed} km/h";
}

var car = new Car("BMW", 120);
car.Accelerate(30);
Console.WriteLine(car); // BMW => 150 km/h


Core concepts: Encapsulation, Inheritance, Polymorphism, Abstraction.

Polymorphism example:

public abstract class Shape
{
public abstract double Area();
}

public class Circle : Shape
{
public double Radius { get; }
public Circle(double r) => Radius = r;
public override double Area() => Math.PI * Radius * Radius;
}

public class Rectangle : Shape
{
public double Width { get; }
public double Height { get; }
public Rectangle(double w, double h) { Width = w; Height = h; }
public override double Area() => Width * Height;
}

Shape[] shapes = { new Circle(3), new Rectangle(4, 5) };
foreach (var s in shapes)
Console.WriteLine(s.Area());


---

### C) Functional Style (in C#)
Emphasis on pure transformations, minimized mutation, composability.

int[] numbers = { 3, 5, 7, 9 };
int sum = numbers.Aggregate((a, b) => a + b);

var squaredEvens = numbers
.Where(n => n % 2 == 0)
.Select(n => n * n)
.ToList();

Console.WriteLine(sum);
Console.WriteLine(string.Join(", ", squaredEvens));


Traits: Lambdas, LINQ pipelines, declarative transformations, easier testing.

---

### D) Declarative Paradigm
Describe WHAT you want, not HOW to iterate.

var products = new[]
{
new { Name = "Laptop", Price = 45000 },
new { Name = "Mouse", Price = 400 },
new { Name = "Monitor", Price = 9000 },
};

var expensive =
from p in products
where p.Price > 5000
orderby p.Price descending
select p.Name;

Console.WriteLine(string.Join(" | ", expensive));


You specify filters and projections; LINQ decides iteration strategy (and can translate to SQL via EF Core).

---
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 noscripts / 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