Developer Advocate
Открыть в Telegram
1 035
Подписчики
Нет данных24 часа
Нет данных7 дней
-130 дней
Архив постов
1 035
یکی از آسیبپذیریهای جدی در پردازش XML، حمله XXE (XML External Entity) است؛ جایی که مهاجم میتواند با تعریف entity خارجی به منابع حساس سیستم دسترسی یابد یا حتی حمله DoS اجرا کند. در .NET معمولا این مشکل زمانی رخ میدهد که توسعهدهنده بیدقتانه از پارسرهای XML پیشفرض (مانند
XmlDocument یا XmlReader) استفاده میکند. کلید پیشگیری، غیرفعال کردن پردازش DTD و external entities است — حتی اگر داده ورودی صرفا از منابع قابل اعتماد دریافت میشود!
در مثال زیر، نحوه امنسازی پارس XML را با XmlReaderSettings مشاهده میکنید:
var settings = new XmlReaderSettings
{
DtdProcessing = DtdProcessing.Prohibit, // غیرفعال کردن پردازش DTD
XmlResolver = null // مانع resolve شدن منابع خارجی
};
using var reader = XmlReader.Create(stream, settings);
var doc = new XmlDocument { XmlResolver = null };
doc.Load(reader);
موارد کلیدی:
- همیشه XmlResolver را روی null قرار دهید (چه در تنظیمات reader و چه خود document).
- پارامتر DtdProcessing را روی Prohibit یا دستکم Ignore قرار دهید — گزینه پیشفرض بسیاری از نسخهها Parse است که ناامن میباشد.
- مراقب باشید که برخی سرویسهای third-party و بعضی Newtonsoft.Json یا WCF نیز ممکن است به صورت زیرساختی از XML استفاده کنند؛ باید تنظیمات امن در آنها نیز اعمال شود.
مطالعه بیشتر با جزییات کاربردی و مثالهای بیشتر را از مستندات رسمی مایکروسافت دنبال کنید:
https://learn.microsoft.com/en-us/dotnet/standard/data/xml/security-guidelines
Application Security (AppSec)
@DeveloperAdvocate 🥑1 035
چهار متریک کلیدی DORA متحولکننده ارزیابی و بهبود عملکرد تیمهای DevOps هستند:
- Lead Time for Changes
- Deployment Frequency
- Mean Time to Restore (MTTR)
- Change Failure Rate
🔎 بیایید نگاهی عمیق به پیادهسازی مانیتورینگ این شاخصها در پروژههای Enterprise مبتنی بر .NET بیندازیم:
۱. Lead Time for Changes: مدت زمان بین کامیت کد تا دیپلوی آن روی Production. یکی از روشهای ساده پایش آن، ثبت timestamp کامیت (مثلاً با Webhook گیت) و مقایسه آن با زمان ثبت دیپلوی (مثلاً با CDN یا Azure DevOps Release):
// ثبت تایماستمپ در Db در مرحله commit و deploy
public class ChangeRecord
{
public string CommitId { get; set; }
public DateTime CommitTime { get; set; }
public DateTime? DeployTime { get; set; }
public TimeSpan? LeadTime => (DeployTime.HasValue) ? DeployTime - CommitTime : null;
}
۲. Deployment Frequency: تعداد دفعات دیپلوی موفق طی یک بازه زمانی (مانند روزانه یا هفتگی). این آمار را میتوان با ثبت لاگهای Deployment Pipeline بهدست آورد.
۳. MTTR: زمان میانگین بازیابی؛ از incident detection تا حل کامل. ثبت زمان آغاز و پایان رخداد، شروع restore و اتمام آن در سرویسهای Observability (مثل Application Insights یا ELK) توصیه میشود.
۴. Change Failure Rate: درصد دیپلویهای منجر به blackout یا Incident نسبت به کل دیپلویها. این داده را میتوان با cross-reference بین deployment log و incident tracking بدست آورد.
یک پترن توصیهشده: ستکردن Event یا Log مناسب در هر استیج کلیدی Release Pipeline و ذخیره نتایج در یک پایگاه مرکزی برای تحلیل در Power BI یا Grafana.
📊 تحلیل عمیق و بصری این متریکها، از حیاتیترین ابزارها برای سازماندهی فنی و تجربه یادگیری DevOps است. هر شاخص به تنهایی سیگنال خاص اما ترکیبی از آنها تصویر واقعی عملکرد تیم را منعکس میکند.
لینک مطالعه بیشتر و پیادهسازی عملی:
https://martinfowler.com/articles/devops-culture-and-practice.html
Advanced CI/CD & Automation
@DeveloperAdvocate 🥑1 035
چطور در دنیای پرتلاطم فناوری، سرتان زیر موج اخبار دفن نشود؟
برای معماری نرمافزار و توسعهدهندگان ارشد، مرز باریکی وجود دارد بین «بیخبری خطرناک» و «غرق شدن در دریای اطلاعات زائد». فیلتر کردن و انتخاب هوشمند محتوا نه فقط باعث صرفهجویی وقت میشود، بلکه به تصمیمسازی بهتر در معماری و انتخاب تکنولوژی منجر خواهد شد.
چند تکنیک عملی برای مهار حجم اطلاعات:
1. معیار طلایی خود را تعریف کنید:
به جای خواندن هر مطلب یا خبر، خودتان را وقف منابع و موضوعاتی کنید که واقعاً روی معماری سیستم یا توسعهی خود اثر مستقیم دارند؛ مثلاً تغییرات معماری .NET، Kubernetes یا مباحث Distributed Systems.
2. مهندسی فید شخصی:
با ابزارهایی مثل Feedly یا Inoreader، فیدهای مورد اعتماد را کاهش دهید و با فیلترهای کلیدی، مطالب بیارزش را خودکار حذف کنید.
3. راهبرد PRACTICAL-CODE:
اگر مطلبی یا مقالهای میخوانید و کدی یا الگوریتمی دارد که مستقیماً میتواند در پروژه، تست یا رشد معماریتان به کار بیاید، همان لحظه بایگانی کنید و سریع آن را در محیط تستی اجرا یا چهبسا به یک Snippet تبدیل کنید.
مثل این الگوی کوچک برای سریعتر پیدا کردن تغییرات کلیدی در نسخههای جدید .NET:
// دریافت لیست APIهای Deprecated در پروژه
var analyzer = new ApiAnalyzer();
var deprecatedList = analyzer.GetDeprecatedApis("YourProject.dll");
foreach(var api in deprecatedList)
Console.WriteLine(api);
4. دستهبندی موضوعی به جای زمانی:
همیشه با خواندن آخرین اخبار شروع نکنید! اجازه دهید دانشی که به موضوعات مهم (مثل Service Mesh یا Event-Driven Architecture) مربوط است، اولویت پیدا کند و بقیه موارد را گهگاه مرور کنید.
5. تقویم یادگیری منظم:
هر هفته دو بازهٔ زمانی بیمزاحمت مشخص کنید که فقط روی یادگیری عمیق و Implementation نمونه متمرکز باشید، نه فقط مرور سرخط خبرها.
### مطالعه بیشتر (انگلیسی)
The Art of Information Filtering – Martin Fowler
#معمارینرمافزار #یادگیریمداوم #مهندسیفناوری
Productivity & Self-Improvement
@DeveloperAdvocate 🥑1 035
بهینهسازی Cold Start و پرفورمنس در Azure Functions و AWS Lambda با .NET
در سناریوهای Serverless با .NET، زمان Cold Start میتواند گلوگاه پرفورمنس باشد؛ خصوصاً در اپلیکیشنهایی با ترافیک burst یا نیاز به پاسخ زیرثانیهای. تفاوت اصلی در زمان بارگذاری runtime .NET (خصوصاً برای isolated process و با dependencyهای سنگین) خود را نشان میدهد.
✅ نکات مؤثر:
- انتخاب ورژن: .NET 8 و بالاتر پیشرفت چشمگیری در startup time نسبت به .NET Core 3.1/5/6 دارند؛ به خصوص با AOT و NativeAOT در پروژههای خاص.
- Trimming و Publish Ready To Run: استفاده از Publish Trimmed و ReadyToRun باعث کاهش سایز و زمان بارگذاری میشود:
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishTrimmed=true /p:PublishReadyToRun=true
- Dependency Injection سبک: سرویسهای پرهزینه (مانند HttpClient، EF DbContext، Logging) را به صورت Singleton، Lazy یا از طریق Service Provider کششده مدیریت کنید؛ تزریق مستقیم Heavy Objectهای Scoped باعث لیز شدن startup میشود.
- Pre-JIT و جبران پذیری: توابع پیشگرم را با تایمر یا پینگ دورهای (Warmup trigger) نگه دارید تا Worker زودتر JIT شود. در AWS Lambda با Provisioned Concurrency و Azure با AlwaysOn این فرآیند قابل مدیریت است.
- Minimal API و Function Startup: جزئیات مینیمالیسم را در Function تعریف کنید؛ مثلاً هنگام استفاده از .NET Isolated ها اصطلاحاً “Function Startup” را مینیمالیستی نگه دارید.
- سیستم I/O خارجی: ارتباطات Redis/SQL/Cloud Storage را به Initialization شاتل نکنید؛ connection pooling مناسب استفاده کنید.
⚡ تفاوت پرفورمنس Azure vs AWS:
- AWS از Provisioned Concurrency برای Warm Instanceها بهره میگیرد (پرداختی اما تضمینی)؛
- Azure Functions Premium/Elastic App Service Plan نیز AlwaysOn و enhanced scaling را در اختیار میگذارد.
- در هر دو، .NET Isolated Process نسبت به In-Process کمی کندتر است ولی ایزولهتر و قابل سفارشیسازیتر است.
🔗 مطالعه بیشتر:
Improve Cold Start Performance of Azure Functions
Cloud Computing (Azure/AWS/GCP) & Serverless
@DeveloperAdvocate 🥑1 035
در معماریهای مدرن مبتنی بر فرانتاند، نیاز به اجرای عملیات رمزنگاری مانند هشینگ یا رمزنگاری متقارن در سمت کلاینت روزبهروز بیشتر میشود—چه برای چک کردن صحت دادهها، چه برای رمزگذاری اطلاعات حساس قبل از ارسال به سرور. Web Cryptography API که در مرورگرها پیادهسازی شده، امکان استفاده از الگوریتمهایی مانند SHA-256 یا AES-GCM را با بهرهگیری از سختافزار دستگاه فراهم میسازد و امنیت و سرعت بالایی ارائه میدهد. توجه داشته باشید که کوئیکفیکسهایی مثل CryptoJS یا هَشینگ ساده با جاوااسکریپت نه فقط امن نیستند، بلکه ممکن است پرفورمنس را نیز مختل کنند.
برای استفاده از این API، کد جاوااسکریپت میتواند آنالیز داده را در سطح کلاینت انجام دهد؛ اما از منظر بکاند .NET و معماری کلان، باید فرض کرد هیچ عملیات رمزنگاری سمت کلاینت جایگزین اعتبارسنجی و رمزنگاری سمت سرور نیست—بلکه صرفاً یک لایهٔ محافظتی بیشتر است.
نمونه کد جاوااسکریپت برای هش SHA-256:
const encoder = new TextEncoder();
const data = encoder.encode("MySecretPassword123");
const hashBuffer = await crypto.subtle.digest("SHA-256", data);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
console.log(hashHex);
برای سناریوهای ترکیبی (مثلاً رمزگذاری فایل در مرورگر و ارسال به ASP.NET Core)، میتوانید با اشتراکگذاری کلیدها یا استفاده از رمزگذاری نامتقارن، امنیت را ارتقا دهید. از لحاظ امنیتی، هیچگاه به رمزنگاری سمت کلاینت بهتنهایی تکیه نکنید؛ اعتبارسنجی غیرقابل اعتماد بودن دادههای کلاینت را جدی بگیرید.
مطالعهٔ تکمیلی (پیشنهاد ویژه برای کسانی که میخواهند عمیقتر بدانند):
Microsoft Docs | Use the Web Cryptography API
#Security #WebCrypto #Architecture #BrowserCryptography
Advanced JavaScript/TypeScript
@DeveloperAdvocate 🥑1 035
🎯 دکوراتورها در TypeScript: متاپروگرامینگ، تزریق وابستگی و لاگگیری پیشرفته
دکوراتورها یکی از جذابترین ابزارهای متاپروگرامینگ در TypeScript هستند که معادلی برای Attributesها یا AOP در #CSharp به شمار میروند. آنها میتوانند روی کلاسها، متدها، پراپرتیها یا پارامترها بنشینند و رفتار/متادیتا را تغییر دهند. به چند کاربرد جدی توجه کنید:
۱. لاگگیری متدها بدون تکرار کد
function Log(target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;
descriptor.value = function (...args: any[]) {
console.log(`[LOG] ${propertyKey} called with`, args);
return originalMethod.apply(this, args);
};
}
class UserService {
@Log
updateUser(id: number, payload: any) {
// عملیات بروزرسانی
}
}
۲. تزریق وابستگی مشابه با .NET
function Injectable(constructor: Function) {
// ریجستر کردن کلاس برای DI Container ساده
DIContainer.register(constructor);
}
@Injectable
class OrderRepository { /* ... */ }
class OrderService {
constructor(private repo: OrderRepository) {}
}
۳. متادیاتای سفارشی با Reflect-metadata
import 'reflect-metadata';
function Entity(entityName: string) {
return function(target: Function) {
Reflect.defineMetadata("entity:name", entityName, target);
}
}
@Entity("User")
class User { }
console.log(Reflect.getMetadata("entity:name", User)); // 'User'
دکوراتورها اجازه میدهند بدون وابستگی به فریمورک خاص، قابلیتهایی شبیه به Dependency Injection, ORM Mapping یا AOP بسازید؛ خصوصاً اگر از TypeScript با فریمورکهایی مثل NestJS استفاده میکنید، اهمیت آن دو چندان است.
مطالعهی پیشنهادی (انگلیسی):
https://blog.logrocket.com/decorator-pattern-in-typescript/
Advanced JavaScript/TypeScript
@DeveloperAdvocate 🥑1 035
تست خودکار زیرساخت، مخصوصاً برای IaC (مثل Terraform)، یک گام بحرانی برای اطمینان از صحت، امنیت و پایداری محیطهای تولید است. ابزارهایی مانند Terratest (برای زیرساخت ابری) و Pester (برای Azure Resource Manager و PowerShell) به شما اجازه میدهند تا مثل تست واحد در کد اپلیکیشن، زیرساخت را هم تست کنید؛ مثلاً آیا یک Virtual Network با تنظیمات صحیح ایجاد شده؟ آیا رول فایروال صرفاً دسترسی لازم را میدهد؟
فرض کنید زیرساخت خود را با Terraform و منابع ابری در Azure تعریف میکنید. تست زیر با استفاده از Pester نمونهای از ارزیابی خودکار یک Resource Group است:
#Requires -Modules Az.Resources, Pester
Describe "Resource Group validation" {
It "Resource Group should exist" {
$rg = Get-AzResourceGroup -Name "my-rg"
$rg | Should -Not -BeNullOrEmpty
}
It "Resource Group should be in correct region" {
$rg = Get-AzResourceGroup -Name "my-rg"
$rg.Location | Should -Be 'westeurope'
}
}
در Terratest (Go)، میتوانید بعد از اجرای terraform apply با کد تستی بررسی کنید که مثلاً یک شبکه بهدرستی provision شده و پارامترهای امنیتی صحیح هستند. تکرار تستها بعد از هر تغییر IaC، جلوی Drift و misconfiguration را به صورت خودکار میگیرد.
نکته تکمیلی: میتوانید تستهای زیرساخت را به Azure DevOps Pipeline یا GitHub Actions اضافه کرده و در هر PR، IaC را بهصورت end-to-end بررسی کنید. این کار بازخورد سریع و ایمنی عملیاتی را تضمین میکند.
مطالعه بیشتر:
https://martinfowler.com/articles/infrastructure-test.html
Advanced CI/CD & Automation
@DeveloperAdvocate 🥑1 035
مدیریت State در برنامههای مقیاسپذیر React همواره چالشی جذاب برای معماران نرمافزار بوده است. Zustand بهعنوان یک State Manager مدرن و lightweight بدون boilerplate اضافی، سینتکس جذاب و API قوی را با عملکرد عالی ترکیب کرده است و حتی در پروژههای بزرگ، جایگزینی خوشدست برای Redux یا Context API است.
بیایید یک مثال پیشرفته و تولیدی از استفاده Zustand را بررسی کنیم که قابلیت ترکیب با WebSocket برای همگامسازی بلادرنگ دادهها را نشان میدهد:
// zustandStore.js
import create from 'zustand'
export const useChatStore = create((set, get) => ({
messages: [],
addMessage: (msg) => set((state) => ({ messages: [...state.messages, msg] })),
ws: null,
connectWs: () => {
const ws = new WebSocket('wss://example.com/socket')
ws.onmessage = (event) => {
get().addMessage(JSON.parse(event.data))
}
set({ ws })
},
sendMessage: (msg) => {
const ws = get().ws
if (ws && ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify(msg))
get().addMessage(msg)
}
}
}))
در این الگو، با جلوگیری از prop drilling و ریرنـدر غیرضروری کامپوننتها، State و side-effectهای WebSocket به شکلی بسیار خوانا و مستقل مدیریت شدهاند. این معماری کاملاً tree-shakable است و حتی میتوان توابع همان store (مانند connectWs یا sendMessage) را بهسادگی به لایه component منتقل کرد:
// SendMessageComponent.jsx
import { useChatStore } from './zustandStore'
function SendMessageComponent() {
const sendMessage = useChatStore((s) => s.sendMessage)
return <button onClick={() => sendMessage({ text: 'Hi Zustand!' })}>Send</button>
}
مزیت ویژهی Zustand برای تیمهایی که نیاز به مدیریت state پیچیده همراه با قابلیت تستپذیری بالا دارند، انعطافپذیری و سادگی integration با هر معماری است (DDD, Hexagonal، CQRS و غیره). State ها را میتوانید به سادگی با Jest/RTL به صورت فانکشنال تست کنید.
مطالعه کامل و مقایسه Zustand با سایر State managerها را از این مقاله عمیق بخوانید:
https://dev.to/raaynaldo/zustand-a-bearbones-state-management-solution-for-react-3j1f
Advanced React Concepts
@DeveloperAdvocate 🥑1 035
الگوهای سرورلس پایگاه داده: طراحی و کوئرینویسی NoSQL در Azure Cosmos DB و AWS DynamoDB برای .NET
تصمیمگیری میان Cosmos DB و DynamoDB معمولاً به معماری workload، latency، و نیازهای polyglot data بستگی دارد—but اصل مشترک، طراحی بههمراه serverless scalability است. یک نکتهی کلیدی: برای رسیدن به عملکرد بهینه، باید مدل دادهتان را "query-driven" و نه relational design محور، پیادهسازی کنید. در NET. با کمک SDK هر سرویس، پترنهایی نظیر single-table/design pattern و request units مختص Cosmos را حرفهای کنترل کنید.
مثال ساده: نوشتن یک کوئری در Cosmos برای فچ داده بدون اسکنی گران، با تعریف index بهینه و استفاده از LINQ:
var container = cosmosClient.GetContainer("db", "items");
var sql = "SELECT * FROM c WHERE c.customerId = @customerId";
var query = new QueryDefinition(sql)
.WithParameter("@customerId", "A123");
var iterator = container.GetItemQueryIterator<Item>(query);
while (iterator.HasMoreResults)
{
foreach (var item in await iterator.ReadNextAsync())
{
// پردازش آیتمها
}
}
در DynamoDB با DynamoDBContext و ساختاری single-table:
var context = new DynamoDBContext(client);
var items = await context.QueryAsync<Order>("CUSTOMER#A123").GetNextSetAsync();
// نتیجه شامل تمام سفارشهای مشتری خاص
نکته حیاتی: partition keyها را با دقت انتخاب کنید—اگر رنج توزیعشان کم باشد، هم DynamoDB و هم Cosmos دچار هاتپارتیشن و throttling میشوند. Cosmos اجازه میدهد throughput را روی container کنترل کنید؛ DynamoDB هم auto-scaling را پیشنهاد میدهد.
برای بهینهسازی، mixed access patterns (مثلاً هم جستجو با customerId و هم orderId) را، با بهرهگیری از secondary indexes (مثل GSI در Dynamo یا composite indexes در Cosmos)، آگاهانه طراحی کنید.
مطالعه عمیق درباره الگوهای مدلینگ سرورلس NoSQL و تفاوتهای بسترها:
https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/modeling-data
#dotnet #CosmosDB #DynamoDB #Serverless #NoSQL
Cloud Computing (Azure/AWS/GCP) & Serverless
@DeveloperAdvocate 🥑1 035
👥 راهنمای عملی برای هدایت جلسات بازبینی طراحی فنی
یک بازبینی مؤثر طراحی صرفاً تورق مستندات نیست؛ بلکه مهارتی پیشرفته در معماری نرمافزار است که تیم را به سمت تصمیمات اصولی و اجتناب از ریورکهای پرهزینه هدایت میکند. ساختار، تسهیل درست و فیدبک هدفمند، سه کلید موفقیت این جلسات حیاتی هستند:
🔹 ساختار پیشنهادی جلسه بازبینی
1. پیش از جلسه، سند طراحی (Design Doc) را حداقل ۲۴h قبل با محوریت اهداف، مفروضات، معماری کلی و موارد بحثبرانگیز به اشتراک بگذارید.
2. جلسه را با سناریوهای بحرانی و سؤالات کلیدی آغاز کنید:
// مثال: ارزیابی انعطافپذیری برای افزودن feature جدید
public interface IPaymentProcessor
{
Task ProcessAsync(Payment payment);
}
// چطور این abstraction میتواند تنوع پردازشگرها را بدون تغییر در consumers پشتیبانی کند؟
3. بحث را بر مبنای دغدغههای واقعی تولید، مقیاسپذیری، maintainability و extensibility هدایت کنید.
4. اگر اختلافنظرها بالا گرفت، از تکنیکهای facilitation مانند Parking Lot یا دو مرحلهای کردن تصمیم استفاده کنید: نخست مشکلات را جمعبندی، سپس گزینههای حل را جمعآوری کنید.
🔹 هنر فیدبک مؤثر
- بازخورد مرتبط، مشخص و Actionable باشد؛ مثال:
«وابستگی مستقیم به IConfiguration در Serviceها میتواند تستپذیری را کاهش دهد. پیشنهاد: Inject کردن مقادیر کانفیگشده.»
- کیفیت فنی را دقیق مرور کنید: آیا Coupling و Cohesion رعایت شده؟ SOLID پیادهسازی شده؟
🔹 نکات تکمیلی
- خروجی جلسه باید یکی از موارد زیر باشد: موافقت نهایی، درخواست بهبود با موارد مشخص یا escalated issue برای تصمیم معماری سطح بالاتر.
- همیشه درسآموختهها را مستندسازی و به الگوهای سازمان اضافه کنید.
مطالعه بیشتر:
How to Run a Great Software Design Review (Martin Fowler)
#ArchitecturalPatterns #TechnicalLeadership #CodeReview #DesignDoc
Technical Leadership & Mentoring
@DeveloperAdvocate 🥑1 035
بحث جدی بومیسازی و پشتیبانی چندزبانه (Globalization/Localization) در ASP.NET Core، تنها ترجمه رشتهها نیست؛ بلکه کلید ورود به بازارهای جهانی و احترام واقعی به فرهنگ کاربری است. بیایید نگاهی عمیقتر به پیادهسازی اصولی بیاندازیم:
۱⃣ فعالسازی Localization:
در
Startup.cs، سرویسهای لازم را اضافه کنید:
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { "fa-IR", "en-US", "fr-FR" }
.Select(c => new CultureInfo(c)).ToList();
options.DefaultRequestCulture = new RequestCulture("en-US");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new QueryStringRequestCultureProvider());
});
۲⃣ تعریف منابع (Resource Files):
برای هر کنترلر/ویو، Resource file ایجاد کنید، مثل:
- Controllers.HomeController.fa.resx
- Controllers.HomeController.en.resx
۳⃣ تزریق IStringLocalizer:
در کنترلرها یا سرویسها، وابستگی را تزریق و استفاده کنید:
public class HomeController : Controller
{
private readonly IStringLocalizer<HomeController> _localizer;
public HomeController(IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}
public IActionResult Index()
{
ViewBag.Welcome = _localizer["WelcomeMessage"];
return View();
}
}
۴⃣ رعایت حساسیت فرهنگی:
- تاریخ/ارز/تقویم باید بر اساس فرهنگ مصرفکننده فرمت شوند.
- اجتناب از فرضیات ضمنی (مثلاً جهت متن LTR/RTL).
۵⃣ انتخاب Culture توسط کاربر:
از middleware پیشرفته یا سیاستهای مبتنی بر کوکی و URL بهره بگیرید تا تجربه زبان انعطافپذیر و پایدار باشد.
مطلب کاملتر و حرفهای با مثالهای پیشرفته:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-8.0
#معماری #Localization #Globalization #ASPNetCore #BestPractices
Quality Attributes & Cross-Cutting Concerns
@DeveloperAdvocate 🥑1 035
🎯 یادگیری مؤثر زبانها و فریمورکهای جدید: استراتژیهایی برای معماران و توسعهدهندگان ارشد
وقتی به سراغ یادگیری یک زبان یا فریمورک تازه میرویم، کلید موفقیت فقط شناخت سینتکس یا API نیست—بلکه در درک عمیق مفاهیم پایه، الگوریتمها و نحوه تطبیق آن با معماری فعلی نهفته است.
۱. بلوکبندی دانش برپایه Domain Problem
برخلاف شیوههای سطحی، پیشنهاد میکنم با یک مسئله واقعی از دامنه خودتان شروع کنید و آن را با ابزار جدید پیادهسازی کنید. مثلاً اگر در داتنت به CQRS و Mediator عادت دارید، معادلهای آنها را در فریمورک جدید پیدا کنید یا بسازید.
۲. مقایسه معماریها و الگوها
الگوهای مورد علاقه خود مثل Dependency Injection، Layered Architecture یا Repository Pattern را استخراج کرده و پیادهسازی آنها را در زبان/فریمورک جدید بررسی کنید. این کار همگرایی مفاهیم را سرعت میدهد و سبب میشود نقاط قوت و ضعف ابزار جدید را بهتر درک کنید.
۳. تستمحور یاد بگیرید (TDD, BDD)
در زبان/فریمورک جدید هم از ابتدا تست بنویسید. نوشتن تستهای Integration و Unit از همان ابتدا باعث میشود ساختاردهی پروژه و الگوهای خطا/شروع، برایتان روشنتر باشد.
مثالی از پیادهسازی یک سرویس ساده CRUD با معماری همراستا در #CSharp:
public interface IProductService
{
Task<Product> GetAsync(Guid id);
Task CreateAsync(Product product);
Task UpdateAsync(Product product);
Task DeleteAsync(Guid id);
}
public class ProductService : IProductService
{
private readonly IRepository<Product> _repo;
public ProductService(IRepository<Product> repo) => _repo = repo;
public Task<Product> GetAsync(Guid id) => _repo.FindAsync(id);
public Task CreateAsync(Product product) => _repo.AddAsync(product);
public Task UpdateAsync(Product product) => _repo.UpdateAsync(product);
public Task DeleteAsync(Guid id) => _repo.RemoveAsync(id);
}
این همان الگویی است که میتوانید آن را مثلاً در Go، Java یا Python با رعایت Dependency Inversion و جداسازی concerns دوباره پیادهسازی کنید.
۴. بررسی RTFM و تکنیکهای out of comfort zone
سند رسمی (RTFM) را دقیق بخوانید، نمونه کدها را با context معماری خود مقایسه کنید و به عمد سراغ بخشهایی بروید که با آنها راحت نیستید (مثلاً Reflection، Concurrency، Messaging).
۵. انتقال دانش به تیم
آموختهها و Pitfallها را مستند کرده و در Code Review یا جلسات Technical Sharing با دیگر اعضا به اشتراک بگذارید. این کار نهتنها باعث تسلط بیشتر شما میشود، بلکه برداشتهای دیگران را هم جذب میکنید.
📖 مقاله پیشنهادی (تکنیکی و عمیق درباره یادگیری زبان جدید برای مهندسین ارشد):
How to Learn a New Programming Language Quickly and Efficiently – devblogs.microsoft.com
Productivity & Self-Improvement
@DeveloperAdvocate 🥑1 035
✨ الگوهای Custom Hook در .NET: بازآفرینی منطق قابل استفاده مجدد و بهینه
در معماریهای مدرن، جداسازی concerns با شدتی بیشتر از هر زمان دیگری حیاتی است. Custom Hookها (الهامگرفته از دنیای React) مفهومی جذاب برای این موضوع هستند: آنها بستههایی از منطق پیچیده را به صورت قابل استفاده مجدد و قابل تست فراهم میکنند.
فرض کنید میخواهید یک Hook برای مدیریت fetching داده با Cancellation و Error Handling پیشرفته بسازید. یک الگو با State Pattern در ترکیب با TaskCompletionSource میتواند سطح بسیار بالایی از قابلیت اطمینان و خوانایی به ارمغان آورد:
public class DataFetcher<T>
{
private readonly Func<CancellationToken, Task<T>> _fetchFunc;
private TaskCompletionSource<T> _tcs = new();
private CancellationTokenSource? _cts;
public bool IsFetching { get; private set; }
public T? Result { get; private set; }
public Exception? Error { get; private set; }
public DataFetcher(Func<CancellationToken, Task<T>> fetchFunc)
{
_fetchFunc = fetchFunc;
}
public async Task<T> FetchAsync()
{
if (IsFetching) throw new InvalidOperationException("Already fetching...");
_cts = new CancellationTokenSource();
_tcs = new TaskCompletionSource<T>();
IsFetching = true;
Result = default;
Error = null;
try
{
var result = await _fetchFunc(_cts.Token);
Result = result;
_tcs.SetResult(result);
return result;
}
catch (Exception ex)
{
Error = ex;
_tcs.SetException(ex);
throw;
}
finally
{
IsFetching = false;
}
}
public void Cancel()
{
if (_cts is { IsCancellationRequested: false })
_cts.Cancel();
}
public Task<T> FetchTask => _tcs.Task;
}
حال میتوانید این کلاس را بهعنوان یک "Hook" منطقی به هر ViewModel یا Service تزریق و با mock یا fake کردن ورودیها به خوبی تست کنید؛ بدون اینکه دچار پیچیدگیهای state پراکنده در سرتاسر سیستم شوید.
🔗 برای مطالعه عمیقتر درباره الگوهای reusable logic و Separation of Concerns در .NET Core، مقاله مارتین فاولر درباره Separated Presentation را از دست ندهید:
https://martinfowler.com/eaaDev/SeparatedPresentation.html
Advanced React Concepts
@DeveloperAdvocate 🥑1 035
💡 معماری Hybrid Cloud با .NET: اتصال دیتاسنتر On-Premises به Cloud
در پروژههایی که نیاز به ترکیب منابع on-premises و cloud وجود دارد (مثلاً migration تدریجی یا الزامات compliance)، یکی از معماریهای مرسوم استفاده از hybrid connectivity با ترکیب ASP.NET Core، Azure Service Bus (یا Event Grid)، و Enterprise Gatewayها است.
🔹 Pattern رایج:
- Backend را به صورت قابل deploy در هر دو محیط (on-prem و cloud) طراحی کنید.
- ارتباطاتِ sensitive را از طریق private peering (مثلاً Azure ExpressRoute یا VPN Gateway) برقرار کنید.
- برای فارسی بودن cross-environment messaging، event-driven communication (مانند استفاده از Service Bus و Queueها) را ترجیح دهید.
🔹 نمونه ارتباط امن و بهینه بین on-prem و Azure Service Bus:
در on-prem یک background service داریم که پیامها را دریافت و پردازش میکند و نیز publish event به سمت Cloud میفرستد؛ برای کاهش latency و افزایش resiliency، retry policy باید پیادهسازی شود:
using Azure.Messaging.ServiceBus;
var client = new ServiceBusClient(connectionString);
var sender = client.CreateSender(queueName);
var message = new ServiceBusMessage("Payload from on-prem");
int retryCount = 0;
const int maxRetries = 5;
while (retryCount < maxRetries)
{
try
{
await sender.SendMessageAsync(message);
break;
}
catch (ServiceBusException ex) when (ex.IsTransient)
{
retryCount++;
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, retryCount)));
}
}
این الگو را میتوانید در background services یا حتی در API gateways به کار بگیرید تا failover مناسبی بین دیتاسنترها داشته باشید.
🔹 نکته معماری:
- همیشه network boundaries و security context را به عنوان یک Bounded Context واقعی در DDD در نظر بگیرید.
- مراقب باشید که dependencyهای cloud-specific را در core business logic تزریق نکنید. Abstraction و DI، کلید تمیز نگه داشتن architecture هستند.
مطالعهی تکمیلی (Microsoft Docs):
https://learn.microsoft.com/en-us/azure/architecture/hybrid/hybrid-architecture-overview
Cloud Computing (Azure/AWS/GCP) & Serverless
@DeveloperAdvocate 🥑1 035
# ✨ gRPC با ASP.NET Core: عمق معماری و ارتباط سرویسها
اگر هنوز در معماری میکروسرویسهای خود از REST برای inter-service communication استفاده میکنید، وقت آن رسیده قدرت gRPC و پروتکلهای باینری را جدیتر بگیرید؛ مخصوصاً زمانی که performance، قرارداد قوی (strong contract) و real-time streaming برایتان حیاتی است.
در gRPC شما با فایلهای
.proto قرارداد خود را تعریف میکنید و سپس کد کلاینت و سرور را اتوماتیک جنریت میکنید، بدون دغدغه هماهنگی مدلها و API versioning:
// Sample .proto
syntax = "proto3";
option csharp_namespace = "OrderService";
service OrderManager {
rpc CreateOrder (OrderRequest) returns (OrderResponse);
}
message OrderRequest {
int32 productId = 1;
int32 quantity = 2;
}
message OrderResponse {
bool success = 1;
string orderId = 2;
}
در ASP.NET Core، فقط کافیست یک سرویس جدید اضافه و inherited کنید:
public class OrderManagerService : OrderManager.OrderManagerBase
{
public override Task<OrderResponse> CreateOrder(OrderRequest request, ServerCallContext context)
{
// کسبوکار ثبت سفارش
return Task.FromResult(new OrderResponse
{
Success = true,
OrderId = Guid.NewGuid().ToString()
});
}
}
سپس در StartUp/Program:
app.MapGrpcService<OrderManagerService>();
## معماری بهینه با Channel Reuse
gRPC connectionها multiplex میشوند (streamهای متعدد روی یک TCP connection)، پس برخلاف HTTP/1.1، هزینه هر call بسیار کاهش مییابد. اگر high-frequency call دارید، اطمینان پیدا کنید HttpClientFactory را با gRPC استفاده میکنید تا connection poolینگ و channel reuse را بهدرستی مدیریت کنید؛ این کار latency و memory leakها را به شکل معناداری کاهش میدهد.
## Protobuf و کلیک عمیقتر
پیادهسازی نوعهای سفارشی، default valueها، و evolve کردن قراردادها (اضافه/حذف فیلدها بدون شکستن وابستگی کلاینتها) تنها بخشی از قابلیتهای منحصر به فرد Protobuf هستند. لازم است همیشه index فیلدها را تغییر ندهید و حذف فیلد به جای replace توصیه نمیشود.
مطالعهی تخصصیتر و مثالهای حرفهای:
https://learn.microsoft.com/en-us/aspnet/core/grpc/
⚡️ اگر معماریتان به مقیاس، عملکرد و type-safety اهمیت میدهد، gRPC را در سکوی میکروسرویسهایتان جدی وارد کنید – قرارداد، performance و تجربه توسعهدهنده متحول میشود.
ASP.NET Core (Advanced)
@DeveloperAdvocate 🥑1 035
🔐 امنیت JWTها: بهترین شیوهها در صدور، اعتبارسنجی، ابطال و نگهداری
در استفاده از JSON Web Token در معماریهای توزیعشده (مخصوصاً .NET)، چند اصل کلیدی برای امنیت باید همیشه رعایت شوند:
۱. توکن کوتاهعمر + Refresh Token
- بهجای استفاده از JWT با عمر بلند، از Access Tokenهای کوتاهمدت (مثلاً ۵ تا ۱۵ دقیقه) استفاده کنید.
- Refresh Token را فقط روی سمت سرور ذخیره کرده و احراز هویت کنید (و نه روی کلاینت).
- پس از ابطال دستی کاربر، Refresh Token را فوراً باطل کنید.
۲. امضا و اعتبارسنجی هوشمند
- همیشه کلید امضای JWT را فقط در سرور نگهداری کنید و با الگوریتم قوی HMAC-SHA256 یا RSA امضا کنید.
- برای جلوگیری از حملات Replay، از
jti (JWT ID) و لیست سیاه توکنهای باطلشده استفاده کنید.
- پیش از پردازش توکن، پارامترهای signature و expiry (exp) و Audience/Issuer را اعتبارسنجی کنید:
var validationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://your-issuer",
ValidateAudience = true,
ValidAudience = "your-audience",
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey)),
ClockSkew = TimeSpan.FromMinutes(3)
};
۳. حذف و ابطال توکنها (Revocation):
- JWTهای بدون State را ذاتاً نمیتوانید ابطال کنید. اما Refresh Tokenها را در دیتابیس یا Redis نگهداری و در صورت نیاز فوری invalidate کنید.
- برای موارد حیاتی (مثلاً سشنهای بانکی)، از Access Token کوتاهمدت و validate کردن jti مقابل لیست بلاکشده بهره ببرید.
۴. ذخیرهسازی امن در کلاینت
- Access Tokenها را هرگز در LocalStorage یا SessionStorage ذخیره نکنید. بهترین انتخاب: HttpOnly Secure Cookie.
- اگر مجبورید از کلاینت استفاده کنید، دوره اعتبار را کوتاه نگه داشته و همه درخواستها را فقط روی HTTPS اجرا کنید.
۵. Token Rotation
- با هر بار استفاده از Refresh Token، باید توکن جدید صادر نمایید و قبلی را منقضی (invalidate) کنید (Sliding Sessions).
🎯 دوستان معمار: هرگز به الگوهای ساده Copy-Paste درباره JWT بسنده نکنید؛ لایههای امنیتی را متناسب با نیاز تجاری و الزامات تهدید پیادهسازی کنید.
مطالعه بیشتر (توصیهی حرفهای — Microsoft Docs):
https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/token-validation
ASP.NET Core (Advanced)
@DeveloperAdvocate 🥑1 035
در معماریهای مدرن مبتنی بر JWT، تنها صدور و امضای توکن کافی نیست؛ باید برای هر سه گام حیاتی Issuance، Validation و Revocation طراحی دقیقی انجام دهید تا سطح حملات و حملات replay را به حداقل برسانید.
🔷 صدور (Issuance):
- توکنها را با claims حداقلی و زمان عمر کوتاه (مثلاً ۵ تا ۱۵ دقیقه) صادر کنید.
- Refresh Token را امن نگه دارید (HttpOnly و Secure).
- برای هر لاگین یا refresh، Refresh Token جدید صادر و قبلی را Invalidate کنید (Token Rotation). این کار جلوی replay و سرقت refresh token را میگیرد.
🔷 اعتبارسنجی (Validation):
- همیشه امضای JWT را با کلید خصوصی/عمومی معتبر بررسی کنید. در .NET:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "YourIssuer",
ValidateAudience = true,
ValidAudience = "YourAudience",
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("super-secret-key")),
ValidateIssuerSigningKey = true,
// اضافه کنید: Reference to blacklist
};
// Custom validation: اگر نیاز به Blacklisting دارید
options.Events = new JwtBearerEvents
{
OnMessageReceived = context =>
{
// استخراج توکن
var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
// بررسی توکن در بلکلیست
if (IsTokenRevoked(token))
{
context.Fail("Token is revoked.");
}
return Task.CompletedTask;
}
};
});
- همیشه ValidateLifetime=true و AutoRenew را فقط در صورت اعتبار Refresh Token انجام دهید.
- بررسی کنید جایی اطلاعات حساس در claims قرار ندادهاید.
🔷 ابطال (Revocation):
- JWT ذاتاً stateless است و ابطال پیچیدهتر میشود؛ چند راهکار:
- Blacklist Table: دیتابیس یا کش کلیدمحور (مثلاً Redis) برای لیست توکنهای باطلشده (JTI).
- Token Rotation: بعد از استفاده از Refresh Token یکبارمصرف، آن را Invalidate کنید.
- Short Expiry: توکن کوتاهعمر برای کاهش آسیب کلید دزدیدهشده.
- در ترکیب با تایید هویت چندمرحلهای و شرایط ریسکمحور (Risk-based auth) این کدها امنتر میشوند.
📚 مطالعه بیشتر و عمیقتر:
JWT Best Practices: Learn JWT Security & Token Management
Application Security (AppSec)
@DeveloperAdvocate 🥑1 035
🔬 Mutation Observer API: رصد تغییرات DOM برای منطق پیچیده UI یا دیباگینگ
آیا تا به حال نیاز داشتهاید خارج از چرخه رندر فریمورک، تغییرات DOM را به دقت زیر نظر بگیرید؟ مخصوصاً در پروژههایی با مولفههای Third-Party یا اسکریپتهایی که خارج از کنترل React/Angular عمل میکنند، Mutation Observer API راهکاری تمیز و توانمند است.
دنبال کردن اضافه/حذف شدن عناصر، تغییر attributeها یا حتی متنی داخلی نودها، با این API دشوار نیست و برای توسعه پلاگینهای بلادرنگ، A/B تست پیشرفته یا دیتابایندینگ غیرمستقیم بسیار مفید است.
یک نمونه برای log کردن هرگونه child جدید در یک بخش مهم از صفحه:
const targetNode = document.getElementById('important-section');
const config = { childList: true, subtree: true };
const observer = new MutationObserver((mutationsList) => {
for(const mutation of mutationsList) {
if (mutation.type === 'childList') {
mutation.addedNodes.forEach(node => {
console.log('Child added:', node);
});
}
}
});
observer.observe(targetNode, config);
// برای توقف: observer.disconnect();
کاربرد حرفهای در UI:
- هماهنگسازی با ویجتهای قدیمی یا Third-Party
- تحلیل رفتار کاربران (Tracking تزریق دکمه/عکس)
- مانیتورینگ امنیتی جاوااسکریپت (شناسایی حملات و تزریقها)
- پروفایل کردن تغییرات برای بهبود Performance
استفاده بیهدف از این ابزار میتواند Performance page را کاهش دهد. همواره محدوده target و نوع Mutation را دقیق کنید، و در زمان مناسب disconnect را فراموش نکنید.
مطالعهی عمیق و معتبر:
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
#JavaScript #DOM #UI #Architecture
Advanced JavaScript/TypeScript
@DeveloperAdvocate 🥑1 035
🎯 JSONB در PostgreSQL: سلاح مخفی برای دادههای نیمهساختیافته و طراحی اسکیمای منعطف
وقتی به دنبال ذخیره دادههای داینامیک و اسکیمای قابل تغییر هستید، اغلب سراغ NoSQL میروید. اما PostgreSQL با نوع داده JSONB قدرت یک دیتابیس relationaal را با انعطافپذیری ذخیرهسازی document ترکیب میکند — و این میتواند معماری شما را متحول کند.
✅ سناریوهای واقعی استفاده:
- ذخیره پراپرتیهای اضافی (attributes) برای آبجکتهایی با فیلدهای متفاوت
- لاگ و telemetry با ساختار متغیر
- استریم ایونتها و دادههای نیمهساختیافته
🔍 نمونه کوئری موثر روی JSONB:
فرض کنیم جداول
Events با فیلد Payload از نوع jsonb داریم:
SELECT *
FROM Events
WHERE Payload ->> 'Status' = 'Completed'
AND (Payload -> 'Duration')::int > 120;
🟦 ادغام پیادهسازی با Dapper/EF Core:
در EF Core میتوانید فیلد jsonb را روی پراپرتی .NET از نوع Dictionary<string,object> یا Type سفارشی مپ کنید.
public class Event
{
public int Id { get; set; }
public string EventType { get; set; }
public Dictionary<string, object> Payload { get; set; }
}
حتی میتوانید با استفاده از attribute هایی مثل [Column(TypeName = "jsonb")] رفتار mapping را کنترل کنید.
💡 Best Practice:
برای دادههای queryable (قابل جستجو) شاخصهای (index) مخصوص jsonb بسازید تا Performance عالی بماند:
CREATE INDEX idx_payload_status ON Events ((Payload ->> 'Status'));
و میتوانید از شاخص GIN برای جستجوی سریعتر در آرایههای داخلی بهره ببرید.
🛡️ نکته معماری:
JSONB همه مشکلات اسکیمای پویا را حل نمیکند. در صورت نیاز به جستجو یا گزارشگیری پیچیده روی فیلدهای درون JSONB، باید indexing و validate data را جدی بگیرید تا سیستم شما به یک “blob-storage” تبدیل نشود.
مطالعه بیشتر:
https://www.cybertec-postgresql.com/en/jsonb-vs-json-postgresql-performance-benefits/
Advanced Database Concepts
@DeveloperAdvocate 🥑1 035
Repost from Pavel Durov
↗️ If you want to reach your full potential and maintain clarity of mind, stay away from addictive substances. My success and health are the result of 20+ years of complete abstinence from alcohol, tobacco, coffee, pills, and illegal drugs. Short-term pleasure isn’t worth your future. 🚭
Here’s what I said about this 7.5 years ago — still true today.
