<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
    <channel>
        <title>نوشته های سمانه شریفی</title>
        <link>https://virgool.io/feed/@sh.samaneh93</link>
        <description></description>
        <language>fa</language>
        <pubDate>2026-04-15 10:31:54</pubDate>
        <image>
            <url>https://files.virgool.io/upload/users/2930601/avatar/avatar.png?height=120&amp;width=120</url>
            <title>سمانه شریفی</title>
            <link>https://virgool.io/@sh.samaneh93</link>
        </image>

                    <item>
                <title>EF Core vs DDD: کِی Navigation Property بگذاریم و کِی فقط ID؟</title>
                <link>https://virgool.io/@sh.samaneh93/ef-core-vs-ddd-%DA%A9%D9%90%DB%8C-navigation-property-%D8%A8%DA%AF%D8%B0%D8%A7%D8%B1%DB%8C%D9%85-%D9%88-%DA%A9%D9%90%DB%8C-%D9%81%D9%82%D8%B7-id-qmz8tvdapl7m</link>
                <description>در توسعه نرم‌افزارهای تجاری، به‌خصوص پروژه‌هایی که از معماری Domain-Driven Design (DDD) و Entity Framework Core استفاده می‌کنند، یکی از چالش‌های رایج این است:«آیا باید Navigation Property داشته باشیم یا فقط ID ذخیره کنیم؟»این سؤال ساده در ظاهر، اما در واقع تأثیر عمیقی روی طراحی دامنه، عملکرد، استقلال ماژول‌ها و مرزبندی Aggregateها دارد.در این مقاله با یک مثال واقعی (سیستم تخفیف در ماژول Booking) بررسی می‌کنیم که چرا و چه زمانی باید Navigation Property را نگه داریم یا حذف کنیم.🧩 بخش ۱: درک Aggregate و قوانین ارتباط در DDDدر معماری DDD، موجودیت‌ها در Aggregate‌ها سازمان‌دهی می‌شوند.هر Aggregate شامل:یک Aggregate Rootموجودیت‌ها یا Value Objectهای داخلی✳ قانون طلایی DDDAggregateها نباید به‌صورت مستقیم به Aggregateهای دیگر ارجاع شیء–به–شیء داشته باشند.یعنی موجودیت‌های یک Aggregate نباید Navigation Property به موجودیت‌های Aggregate دیگر داشته باشند.این قانون باعث:استقلال دامنه‌هاکاهش couplingجلوگیری از بارگذاری‌های غیرضروریشفافیت قوانین تجاریمی‌شود.🧩 بخش ۲: نقش Navigation Property در EF CoreEF Core اعتقاد دارد روابط را بهتر بفهمد، بنابراین معمولاً وجود Navigation Property مثل:public Service Service { get; set; }
به آن کمک می‌کند:Lazy/Eager LoadingInclude()Mapping آسان‌تر به DTOTracking بهتراما در DDD، این دقیقاً چیزی است که نباید برای Aggregateهای مختلف استفاده شود.🧩 بخش ۳: نمونه موردی — DiscountRule و Serviceفرض کنیم در یک سیستم رزرو خدمات (Booking System) ساختاری شبیه زیر داریم:DiscountCard (Aggregate Root)DiscountRule (Entity)Service (Aggregate Root مستقل)DiscountRule:public class DiscountRule : BaseEntity
{
    public Guid DiscountCardId { get; set; }
    public Guid? ServiceId { get; set; }   // فقط شناسه
    public DateTime? FromDate { get; set; }
    public DateTime? ToDate { get; set; }
    public decimal? Price { get; set; }
    public decimal? Percent { get; set; }

    public DiscountCard DiscountCard { get; set; }  // داخل Aggregate
}
نکته مهمDiscountRule و DiscountCard متعلّق به یک Aggregate هستند، اما Service نه.بنابراین Navigation زیر حذف می‌شود:// public Service Service { get; set; }   ❌
🎨 بخش ۴: شماتیک بصری Aggregateها✔ ارتباط مجاز (درون یک Aggregate)DiscountCard (Root)
    └── DiscountRule
تميیز:DiscountRule → DiscountCard   ✔ Navigation Allowed
❌ ارتباط غیرمجاز (دو Aggregate مستقل)DiscountRule ----X----&gt; Service
چرا؟چون:Aggregateها باید مستقل باشنداعمال قوانین دامنه نباید مرز Aggregateها را بشکندEF Core نباید این دو را در یک درخت آبجکت لود کند🧩 بخش ۵: اگر Navigation حذف شود چه می‌شود؟🔹 رفتار درست در DDDDiscountRule فقط شناسه Service را نگه می‌دارد:public Guid? ServiceId { get; set; }
اگر Service لازم شد، در لایه Application بازیابی می‌شود:var rule = await _ruleRepo.GetByIdAsync(id);
var service = await _serviceRepo.GetByIdAsync(rule.ServiceId);

return new DiscountRuleDto(rule, service);
Aggregate DiscountCard هیچ وابستگی به Service پیدا نمی‌کند.🧩 بخش ۶: آیا همیشه باید Navigation را حذف کنیم؟خیر!نوع رابطهNavigationتوضیحEntity → Root (در یک Aggregate)✔ مجازمثل DiscountRule → DiscountCardAggregate → Aggregate❌ ممنوعمثل DiscountRule → ServiceValue Object → Entity✔ مجازمشکلی نداردچند به چند میان Aggregateها❌ ممنوعباید به صورت ID طراحی شود🚀 بخش ۷: مزایای این کار در پروژه واقعی✔ استقلال ماژول‌هاAggregate رزرو (Booking) به Aggregate Service وابسته نمی‌شود.✔ جلوگیری از بارگذاری غیرضروریIncludeهای سنگین حذف می‌شوند.✔ سادگی قوانین دامنههر Aggregate قوانین خودش را کنترل می‌کند.✔ امکان تغییر در آیندهسرویس‌ها یا قوانین تخفیف می‌توانند بدون شکستن دیگری تغییر کنند.✔ پیاده‌سازی بهتر CQRS و MicroservicesAggregateها مستقل‌تر می‌شوند.🎯 نتیجه‌گیریتمایز بین Navigation Property و Reference by ID یک تصمیم ساده نیست، بلکه قلب معماری DDD است.به‌صورت خلاصه:اگر دو موجودیت داخل یک Aggregate هستند → Navigation بگذارید.اگر دو موجودیت از دو Aggregate متفاوت هستند → Navigation را حذف کنید و فقط ID نگه دارید.با رعایت این اصل، سیستم شما:مقیاس‌پذیرترتمیزترمستقل‌تربا قابلیت توسعه بیشترخواهد بود.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Mon, 24 Nov 2025 19:51:14 +0330</pubDate>
            </item>
                    <item>
                <title>درک کامل Delegate و Func در C#</title>
                <link>https://virgool.io/@sh.samaneh93/%D8%AF%D8%B1%DA%A9-%DA%A9%D8%A7%D9%85%D9%84-delegate-%D9%88-func-%D8%AF%D8%B1-c-jgvlhmamh90s</link>
                <description>در زبان C#، توابع هم داده هستند.یعنی می‌توانیم آن‌ها را به متغیرها نسبت دهیم، به عنوان پارامتر به متدها ارسال کنیم، یا حتی در لیست‌ها ذخیره کنیم.پایه‌ی این قابلیت در C#، مفهومی است به نام Delegate.Delegateها به همراه Func&lt;&gt; و Action&lt;&gt; یکی از مهم‌ترین ابزارهای برنامه‌نویسی مدرن در دات‌نت محسوب می‌شوند.در این مقاله به‌صورت مفهومی و کاربردی یاد می‌گیریم Delegate چیست، Func چه تفاوتی دارد، و در چه موقعیت‌هایی استفاده می‌شوند.🔹 Delegate چیست؟به زبان ساده، Delegate نوعی متغیر است که می‌تواند به یک تابع اشاره کند.در واقع اشاره‌گر به تابع (Function Pointer) در دات‌نت است.با استفاده از Delegate می‌توانیم تابعی را:در یک متغیر نگه داریمبه متد دیگر ارسال کنیمیا در زمان اجرا تصمیم بگیریم کدام تابع اجرا شود✳️ مثال ساده از تعریف و استفاده از Delegate// تعریف delegate
delegate void MyDelegate();

// تابعی که با آن سازگار است
void SayHello()
{
    Console.WriteLine(&quot;Hello!&quot;);
}

// استفاده از delegate
MyDelegate d = SayHello;
d(); // خروجی: Hello!
در این مثال:MyDelegate نوعی delegate است که به هر تابعی با امضای void() اشاره می‌کند.متغیر d اکنون تابع SayHello را در خود نگه می‌دارد.با اجرای d() در واقع همان تابع SayHello فراخوانی می‌شود.🔸 Delegate با پارامتر و خروجیDelegateها می‌توانند پارامتر ورودی و مقدار خروجی هم داشته باشند:delegate int MathOperation(int a, int b);

int Add(int x, int y) =&gt; x + y;
int Multiply(int x, int y) =&gt; x * y;

void RunOperation(MathOperation op)
{
    Console.WriteLine(op(3, 4));
}

RunOperation(Add);      // 7
RunOperation(Multiply); // 12
در این مثال، تابع RunOperation خودش تابعی از نوع MathOperation را به عنوان پارامتر دریافت می‌کند.این دقیقاً همان مفهوم ارسال تابع به تابع دیگر (Higher-Order Function) است.🔸 Lambda و Delegateدر C# برای راحت‌تر نوشتن delegateها، از Lambda Expression استفاده می‌شود.Lambda یعنی تابع بی‌نام:MathOperation subtract = (a, b) =&gt; a - b;
Console.WriteLine(subtract(10, 3)); // خروجی: 7
🔹 Func&lt;&gt; چیست؟Func&lt;&gt; در واقع یک نوع Delegate آماده است که در خود دات‌نت تعریف شده.نیازی نیست هر بار delegate جدید بنویسی.قانون کلی:Func همیشه خروجی دارد (Return Value).✳️ ساختار FuncFunc&lt;T1, T2, ..., TResult&gt;
تمام پارامترهای اولی (T1, T2, ...) ورودی تابع هستندآخرین پارامتر (TResult) خروجی تابع است📘 مثال‌های ساده از FuncFunc&lt;int&gt; getNumber = () =&gt; 5;
Console.WriteLine(getNumber()); // 5

Func&lt;int, int&gt; square = x =&gt; x * x;
Console.WriteLine(square(4)); // 16

Func&lt;int, int, int&gt; add = (a, b) =&gt; a + b;
Console.WriteLine(add(3, 7)); // 10
در همهٔ این مثال‌ها، ما تابع را در قالب یک متغیر از نوع Func ذخیره کرده‌ایم.🔸 Action در مقابل Funcاگر تابع خروجی ندارد، از Action استفاده می‌کنیم:نوعخروجی دارد؟مثالFunc&lt;int, int&gt;✅ دارد (int برمی‌گرداند)x =&gt; x * 2Action&lt;string&gt;❌ ندارد (void است)x =&gt; Console.WriteLine(x)🧩 ترکیب Delegate و Func در دنیای واقعیدر سیستم‌های مدرن (مثلاً ASP.NET Core)، از Func و delegate برای طراحی صف کار (Background Queue) استفاده می‌شود.مثلاً متد زیر در یک صف کاری وجود دارد:void Enqueue(Func&lt;CancellationToken, Task&gt; workItem);
یعنی:تابعی را بفرست که یک CancellationToken می‌گیرد و یک Task برمی‌گرداند (یعنی کاری async انجام می‌دهد).کاربردش چیست؟ارسال کارهایی مثل ارسال ایمیل، ثبت گزارش، یا Sync با APIها به صفی که در پس‌زمینه اجرا می‌شود.مثال:queue.Enqueue(async token =&gt;
{
    await Task.Delay(2000, token);
    Console.WriteLine(&quot;Job done!&quot;);
});
🔍 مزیت‌های استفاده از Delegate و Func✅ جدا کردن منطق از ساختار✅ افزایش انعطاف در طراحی (قابلیت پاس دادن رفتار به متدها)✅ کاهش تکرار کد✅ پشتیبانی از الگوهای تابعی (Functional Patterns)✅ کاربرد گسترده در LINQ، async/await، و eventها🧠 جمع‌بندیمفهومتعریفمثالDelegateنوع داده‌ای که به یک تابع اشاره می‌کندdelegate void MyDelegate();FuncDelegate آماده برای توابع دارای خروجیFunc&lt;int, int, int&gt; add = (a,b)=&gt;a+b;ActionDelegate آماده برای توابع بدون خروجیAction&lt;string&gt; show = s =&gt; Console.WriteLine(s);🔹 جمله طلاییDelegate پایه‌ی همه‌ی الگوهای callback، event، async task، LINQ و middleware در دات‌نت است.Func&lt;&gt; و Action&lt;&gt; فقط نسخه‌های راحت‌تر و از پیش‌تعریف‌شدهٔ آن هستند.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Mon, 27 Oct 2025 15:20:01 +0330</pubDate>
            </item>
                    <item>
                <title>چرا به Dependency Injection و Dependency Inversion نیاز داریم؟</title>
                <link>https://virgool.io/@sh.samaneh93/%DA%86%D8%B1%D8%A7-%D8%A8%D9%87-dependency-injection-%D9%88-dependency-inversion-%D9%86%DB%8C%D8%A7%D8%B2-%D8%AF%D8%A7%D8%B1%DB%8C%D9%85-xlktvlvotggy</link>
                <description>به عنوان برنامه‌نویس، ما همیشه با سیستم‌هایی سروکار داریم که از چندین کلاس و کامپوننت تشکیل شده‌اند.هر کلاس معمولاً دو نوع مسئولیت دارد:منطق اصلی خودش (Business Logic)استفاده از سرویس‌ها یا کلاس‌های دیگر برای انجام وظایف جانبیبرای درک بهتر، بیایید یک مثال واقعی را بررسی کنیم 👇🔹 مثال: سیستم ثبت سفارش (Order System)فرض کنید کلاسی داریم به نام OrderService که مسئول مدیریت سفارش‌هاست.اما برای ثبت هر سفارش، نیاز داریم پرداخت (Payment) هم انجام شود.ساده‌ترین حالت ممکن این است که OrderService خودش مستقیماً یک نمونه از PaymentService بسازد:public class OrderService
{
    private PaymentService _paymentService = new PaymentService();

    public void PlaceOrder(Order order)
    {
        _paymentService.Process(order);
    }
}

public class PaymentService
{
    public void Process(Order order)
    {
        Console.WriteLine(&quot;پرداخت سفارش انجام شد.&quot;);
    }
}
در نگاه اول ساده به نظر می‌رسد، اما در واقع یک مشکل جدی وجود دارد 👇OrderService به شدت به PaymentService وابسته است.اگر بخواهیم نوع پرداخت را تغییر دهیم (مثلاً PayPal یا Stripe اضافه کنیم) یا در تست‌ها از نسخه‌ی Fake استفاده کنیم،باید داخل کد OrderService تغییر دهیم — این یعنی وابستگی شدید (Tight Coupling).اینجاست که مفاهیم Inversion of Control (IoC)، Dependency Injection (DI) و Dependency Inversion Principle (DIP) وارد می‌شوند.🌀 Inversion of Control (IoC) — وارونگی کنترلدر طراحی سنتی، هر کلاس خودش کنترل ساخت وابستگی‌ها را دارد.اما در IoC، این کنترل وارونه می‌شود — یعنی ساخت و مدیریت وابستگی‌ها از درون کلاس گرفته می‌شود و به بیرون سپرده می‌شود.به زبان ساده:به جای اینکه کلاس بگوید &quot;من می‌سازم و استفاده می‌کنم&quot;، می‌گوید &quot;به من بده تا استفاده کنم&quot;.❌ بدون IoCpublic class OrderService
{
    public void PlaceOrder(Order order)
    {
        var paymentService = new PaymentService();
        paymentService.Process(order);
    }
}
در اینجا کنترل ساخت درون OrderService است، یعنی خودش تصمیم می‌گیرد از چه نوع PaymentService استفاده کند.✅ با IoCpublic class OrderService
{
    private readonly IPaymentService _paymentService;

    public OrderService(IPaymentService paymentService)
    {
        _paymentService = paymentService;
    }

    public void PlaceOrder(Order order)
    {
        _paymentService.Process(order);
    }
}
و حالا فقط یک interface داریم که قرارداد (contract) را مشخص می‌کند:public interface IPaymentService
{
    void Process(Order order);
}
و چند پیاده‌سازی مختلف:public class CreditCardPaymentService : IPaymentService
{
    public void Process(Order order)
    {
        Console.WriteLine(&quot;پرداخت با کارت اعتباری انجام شد.&quot;);
    }
}

public class PayPalPaymentService : IPaymentService
{
    public void Process(Order order)
    {
        Console.WriteLine(&quot;پرداخت با PayPal انجام شد.&quot;);
    }
}
در این حالت، OrderService فقط می‌گوید &quot;من به یک IPaymentService نیاز دارم&quot;،و دیگر خودش تصمیم نمی‌گیرد از چه نوعی استفاده کند — این یعنی کنترل معکوس شده است (Inversion of Control).💉 Dependency Injection (DI) — تزریق وابستگیDependency Injection یکی از روش‌های پیاده‌سازی IoC است.در این روش، وابستگی‌ها از بیرون (مثلاً از طریق constructor) تزریق می‌شوند.در مثال بالا، وقتی برنامه اجرا می‌شود، یک IoC Container نمونه‌ی مناسب از IPaymentService را ساخته و به OrderService تزریق می‌کند:var payment = new CreditCardPaymentService();
var orderService = new OrderService(payment);
orderService.PlaceOrder(new Order());
در ASP.NET Core این کار به‌صورت خودکار و با ثبت در Startup.cs انجام می‌شود:public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped&lt;IPaymentService, CreditCardPaymentService&gt;();
    services.AddScoped&lt;OrderService&gt;();
}
حالا اگر خواستیم از PayPal استفاده کنیم، فقط باید ثبت را تغییر دهیم:services.AddScoped&lt;IPaymentService, PayPalPaymentService&gt;();
بدون اینکه حتی یک خط از OrderService را تغییر دهیم.این یعنی کاهش وابستگی (Loose Coupling) و افزایش انعطاف‌پذیری.🧩 Dependency Inversion Principle (DIP)اصل پنجم از SOLID می‌گوید:ماژول‌های سطح بالا نباید به ماژول‌های سطح پایین وابسته باشند.هر دو باید به Abstraction (interface یا abstract class) وابسته باشند.در مثال ما:OrderService یک ماژول سطح بالا است (منطق اصلی).CreditCardPaymentService یا PayPalPaymentService ماژول‌های سطح پایین هستند (جزئیات).هر دو به IPaymentService وابسته‌اند (Abstraction).بنابراین:اگر روش پرداخت تغییر کند، نیازی نیست OrderService تغییر کند.جزئیات وابسته به abstraction هستند، نه برعکس.این یعنی اصل Dependency Inversion کاملاً رعایت شده است.🧠 Type Broker (یا IoC Container) — مغز کنترل وابستگی‌هادر سیستم‌های واقعی با ده‌ها یا صدها کلاس و سرویس، ساخت دستی وابستگی‌ها دشوار می‌شود.اینجاست که Type Broker یا همان IoC Container وارد عمل می‌شود.نقش Type Broker:ثبت سرویس‌ها (Registration)ساخت و تزریق خودکار وابستگی‌ها (Resolution)مدیریت طول عمر اشیاء (Lifetime)مثال در ASP.NET Core:public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient&lt;IPaymentService, PayPalPaymentService&gt;();
    services.AddScoped&lt;OrderService&gt;();
}
وقتی OrderService فراخوانی شود، سیستم به‌صورت خودکار:PayPalPaymentService را می‌سازد،آن را در سازنده‌ی OrderService تزریق می‌کند،و طول عمر آن را مطابق تنظیمات مدیریت می‌کند.به همین دلیل از آن به عنوان Type Broker یا Dependency Resolver یاد می‌شود.🔁 ارتباط بین IoC، DI، DIP و Type BrokerمفهومتوضیحنقشIoCوارونگی کنترل ساخت وابستگی‌هافلسفه و ایدهDIروش اجرای IoC از طریق تزریق وابستگی‌هاپیاده‌سازیDIPاصل طراحی بر اساس abstraction، نه implementationقانون طراحیType Broker / IoC Containerابزار مدیریت و تزریق خودکار وابستگی‌هامکانیزم اجرایی🧱 مزایای استفاده از این مفاهیم✅ کاهش وابستگی (Loose Coupling) — کلاس‌ها به abstraction وابسته‌اند، نه به همدیگر.✅ افزایش تست‌پذیری (Testability) — می‌توان Mock یا Fake تزریق کرد.✅ انعطاف‌پذیری بالا (Flexibility) — تغییر در جزئیات بدون تغییر در منطق اصلی.✅ نگهداری آسان (Maintainability) — Dependencyها متمرکز و قابل کنترل هستند.✅ مقیاس‌پذیری (Scalability) — با وجود Type Broker، کل سیستم منظم و قابل پیش‌بینی می‌ماند.🔚 نتیجه‌گیریدر معماری مدرن، مفاهیم IoC، DI، DIP و Type Broker مکمل یکدیگر هستند.با به‌کارگیری آن‌ها:وابستگی‌ها قابل کنترل می‌شوند،کدها قابل تست و نگهداری می‌مانند،و سیستم به‌صورت ماژولار و مقیاس‌پذیر رشد می‌کند.به زبان ساده:🔸 DIP می‌گوید: به abstraction وابسته شو.🔸 IoC می‌گوید: کنترل ساخت را به بیرون بده.🔸 DI می‌گوید: بگذار من تزریقش کنم.🔸 Type Broker می‌گوید: من کل این فرآیند را برایت مدیریت می‌کنم.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Tue, 14 Oct 2025 14:30:25 +0330</pubDate>
            </item>
                    <item>
                <title>مقایسه ADO.NET، EF Core و Dapper در توسعه اپلیکیشن‌های دات‌نت</title>
                <link>https://virgool.io/@sh.samaneh93/%D9%85%D9%82%D8%A7%DB%8C%D8%B3%D9%87-adonet-ef-core-%D9%88-dapper-%D8%AF%D8%B1-%D8%AA%D9%88%D8%B3%D8%B9%D9%87-%D8%A7%D9%BE%D9%84%DB%8C%DA%A9%DB%8C%D8%B4%D9%86-%D9%87%D8%A7%DB%8C-%D8%AF%D8%A7%D8%AA-%D9%86%D8%AA-xe3dkq9gwzgi</link>
                <description>در توسعه نرم‌افزارهای دات‌نت، تعامل با پایگاه داده یکی از بخش‌های حیاتی است. ابزارها و روش‌های مختلفی برای این کار وجود دارد که سه مورد پرکاربرد آن‌ها عبارتند از: ADO.NET، Entity Framework Core (EF Core) و Dapper. در این مقاله به بررسی تفاوت‌ها، مزایا و معایب هر یک می‌پردازیم.1. سطح انتزاع و راحتی استفادهADO.NET:ADO.NET سطح انتزاع پایینی دارد. توسعه‌دهنده مستقیماً با Connection، Command و DataReader کار می‌کند و مسئول مدیریت کامل داده‌ها و اتصال است. هرگونه نگاشت داده‌ها به اشیاء، دستی انجام می‌شود.EF Core:EF Core یک ORM کامل است و سطح بالایی از انتزاع را ارائه می‌دهد. توسعه‌دهنده با کلاس‌ها و آبجکت‌ها کار می‌کند و EF Core خود SQL را تولید و اجرا می‌کند. نگاشت بین جداول و کلاس‌ها به صورت خودکار انجام می‌شود.Dapper:Dapper یک Micro ORM است که ترکیبی از راحتی و کنترل را ارائه می‌دهد. توسعه‌دهنده SQL را خودش می‌نویسد، ولی نگاشت داده‌ها به کلاس‌ها به صورت خودکار انجام می‌شود. سطح انتزاع آن بین ADO.NET و EF Core قرار دارد.2. نوشتن SQLADO.NET: همیشه نیازمند نوشتن SQL به صورت دستی است.EF Core: SQL به صورت خودکار تولید می‌شود، ولی امکان اجرای Raw SQL هم وجود دارد.Dapper: SQL به صورت دستی نوشته می‌شود، ولی نگاشت به کلاس‌ها اتوماتیک انجام می‌شود.3. مدیریت اتصال و تراکنش‌هاADO.NET: توسعه‌دهنده مسئول باز و بسته کردن اتصال و مدیریت تراکنش‌ها است.EF Core: EF Core اتصال و تراکنش را مدیریت می‌کند، اما کنترل دستی نیز امکان‌پذیر است.Dapper: مشابه ADO.NET، توسعه‌دهنده باید اتصال و تراکنش را مدیریت کند.4. کاراییADO.NET: سریع‌ترین روش به دلیل عدم وجود لایه انتزاعی اضافه.Dapper: بسیار سریع و نزدیک به ADO.NET، زیرا تنها وظیفه نگاشت داده‌ها را انجام می‌دهد و هیچ ORM کامل ندارد.EF Core: کمی کندتر از ADO.NET و Dapper، زیرا عملیات Tracking و Lazy Loading و دیگر ویژگی‌های ORM اضافه را دارد.5. نگاشت داده به کلاس‌هاADO.NET: باید دستی داده‌ها را به کلاس‌ها یا اشیاء تبدیل کرد.EF Core: نگاشت خودکار با Conventions یا Fluent API انجام می‌شود.Dapper: نگاشت خودکار به کلاس‌ها انجام می‌شود، سریع و سبک، اما امکانات ORM کامل EF را ندارد.6. مزایا و معایبویژگیADO.NETEF CoreDapperسطح انتزاعپایینبالامتوسطسرعتبسیار سریعکمی کندتربسیار سریعیادگیریساده برای SQL، پیچیده برای پروژه بزرگنیاز به یادگیری EF و LINQساده و نزدیک به SQLنگهداری کددشوار در پروژه‌های بزرگآسان و خوانامتوسطامنیت در برابر SQL Injectionباید مراقب باشیدپارامترایز شده، امنپارامترایز شده، امنویژگی‌های ORMنداردکامل (tracking, lazy loading, relationships)محدود (tracking ندارد)مناسب برای پروژهپروژه‌های کوچک یا نیازمند سرعت بالاپروژه‌های بزرگ و پیچیدهپروژه‌های میانی که هم سرعت و هم نگاشت اتوماتیک نیاز دارندجمع‌بندیADO.NET: بهترین انتخاب برای کنترل کامل و کارایی بالا، اما نگهداری و توسعه کد پیچیده‌تر است.EF Core: مناسب پروژه‌های بزرگ و پیچیده که خوانایی و نگهداری کد اهمیت دارد.Dapper: ترکیبی از سرعت و راحتی نگاشت داده‌ها به کلاس‌ها، گزینه‌ای مناسب برای پروژه‌هایی که نمی‌خواهند از ORM کامل استفاده کنند.💡 نتیجه‌گیری:انتخاب بین این سه ابزار بستگی به نیاز پروژه، پیچیدگی سیستم و اولویت توسعه‌دهنده دارد. برای پروژه‌های کوچک و نیازمند کارایی، ADO.NET؛ برای پروژه‌های بزرگ و maintainable، EF Core؛ و برای پروژه‌هایی که هم سرعت و هم راحتی mapping می‌خواهند، Dapper پیشنهاد می‌شود.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Sun, 28 Sep 2025 09:09:23 +0330</pubDate>
            </item>
                    <item>
                <title>Reflection در C#</title>
                <link>https://virgool.io/codenevis/reflection-%D8%AF%D8%B1-c-zxf1jbubtqk1</link>
                <description>Reflection یکی از قابلیت‌های قدرتمند در زبان C# و .NET است که به برنامه‌نویس اجازه می‌دهد در زمان اجرا (Runtime) به ساختار و متادیتای (Metadata) برنامه دسترسی پیدا کند.با Reflection می‌توانیم اطلاعاتی مثل کلاس‌ها، متدها، پراپرتی‌ها، فیلدها و Attributeها را بررسی کرده یا حتی آن‌ها را به صورت پویا (Dynamic) اجرا کنیم.به بیان ساده، Reflection یعنی نگاه کردن به داخل اسمبلی (Assembly) در زمان اجرا.چرا Reflection مهم است؟تصور کنید می‌خواهید:تمام متدهای یک کلاس را در زمان اجرا پیدا کنید.یک متد خاص را بدون دانستن نامش در زمان کامپایل اجرا کنید.تمام ثابت‌های (const) یک کلاس را به‌صورت داینامیک لیست کنید.ابزاری بسازید که بدون کدنویسی دستی، API یا CRUD تولید کند.تمام این کارها با Reflection ممکن است.مثال‌های عملی۱. گرفتن اطلاعات یک کلاسpublic class Person
{
    public string Name { get; set; }
    public int Age { get; set; }

    public void SayHello() =&gt; Console.WriteLine($&quot;Hello, I am {Name}&quot;);
}
در زمان اجرا می‌توانیم اطلاعات کلاس را بگیریم:var type = typeof(Person);

Console.WriteLine(type.Name);       // Person
Console.WriteLine(type.Namespace);  // فضای نام

foreach (var prop in type.GetProperties())
{
    Console.WriteLine($&quot;Property: {prop.Name} - {prop.PropertyType}&quot;);
}
۲. اجرای متد در زمان اجراvar person = new Person { Name = &quot;Ali&quot; };
var type = person.GetType();
var method = type.GetMethod(&quot;SayHello&quot;);
method.Invoke(person, null);
حتی اگر نام متد را از قبل ندانیم، در زمان اجرا می‌توانیم آن را پیدا کرده و اجرا کنیم.۳. گرفتن تمام ثابت‌ها (Const) با Reflectionpublic static class Constants
{
    public const string AppName = &quot;Sametrix&quot;;
    public const string Version = &quot;1.0&quot;;
}
کلاس Helper:public static class ReflectionHelper
{
    public static IEnumerable&lt;string&gt; GetConstStrings&lt;T&gt;()
    {
        return typeof(T)
            .GetFields(System.Reflection.BindingFlags.Public |
                       System.Reflection.BindingFlags.Static |
                       System.Reflection.BindingFlags.FlattenHierarchy)
            .Where(fi =&gt; fi.IsLiteral &amp;&amp; !fi.IsInitOnly &amp;&amp; fi.FieldType == typeof(string))
            .Select(fi =&gt; fi.GetRawConstantValue().ToString());
    }
}
و استفاده:var values = ReflectionHelper.GetConstStrings&lt;Constants&gt;();
// خروجی: [ &quot;Sametrix&quot;, &quot;1.0&quot; ]
کاربردهای ReflectionORMها مثل Entity Framework برای نگاشت کلاس‌ها به دیتابیس.Dependency Injection برای کشف و ثبت سرویس‌ها.Serialization / Deserialization مثل JSON.Net.Attribute-based programming (مثل [Authorize], [HttpGet]).ساخت ابزارهای داینامیک (مثل گرفتن لیست ثابت‌ها یا ساخت فرم و API اتوماتیک).مزایا و معایب✅ مزایاانعطاف‌پذیری بالا در طراحی سیستم‌های داینامیک.امکان کار با کدی که در زمان کامپایل شناخته‌شده نیست.مناسب برای ساخت ابزارها، فریم‌ورک‌ها و کتابخانه‌ها.❌ معایبسرعت پایین‌تر نسبت به دسترسی مستقیم.پیچیدگی بیشتر کد و سخت‌تر شدن دیباگ.خطاهای زمان اجرا در صورت استفاده اشتباه.نکات Best Practiceتا حد ممکن کم استفاده کنید. فقط در جاهایی که واقعاً نیاز است.برای عملیات پرتکرار، نتایج Reflection را Cache کنید تا سرعت بیشتر شود.اگر می‌شود با Generic یا Expression حل کرد، از آن‌ها استفاده کنید.جمع‌بندیReflection یک ابزار قدرتمند در C# است که امکان بررسی و تغییر ساختار برنامه در زمان اجرا را فراهم می‌کند. این قابلیت در بسیاری از فریم‌ورک‌ها و ابزارهای بزرگ مثل Entity Framework، ASP.NET Core و Newtonsoft.Json استفاده شده است.با این حال باید با احتیاط استفاده شود، چون می‌تواند کارایی و خوانایی کد را کاهش دهد.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Thu, 25 Sep 2025 09:50:28 +0330</pubDate>
            </item>
                    <item>
                <title>IHostedService و BackgroundService در .NET Core</title>
                <link>https://virgool.io/@sh.samaneh93/ihostedservice-%D9%88-backgroundservice-%D8%AF%D8%B1-net-core-vtlfjsxxkzwg</link>
                <description>در بسیاری از برنامه‌های نرم‌افزاری، علاوه بر پردازش درخواست‌های کاربر، نیاز به انجام کارهای پس‌زمینه وجود دارد. این کارها می‌توانند شامل پردازش صف‌ها، ارسال ایمیل، جمع‌آوری آمار یا اجرای عملیات زمان‌بندی‌شده باشند. در .NET Core، این نیاز با استفاده از اینترفیس IHostedService و کلاس BackgroundService به‌صورت استاندارد پشتیبانی می‌شود. این مقاله به بررسی این دو مفهوم، تفاوت‌ها و نحوه استفاده آن‌ها می‌پردازد.IHostedService چیست؟IHostedService یک اینترفیس پایه برای سرویس‌های پس‌زمینه در .NET Core است. اینترفیس شامل دو متد اصلی می‌شود:public interface IHostedService
{
    Task StartAsync(CancellationToken cancellationToken);
    Task StopAsync(CancellationToken cancellationToken);
}
StartAsync: هنگام شروع برنامه اجرا می‌شود و وظیفه راه‌اندازی سرویس را دارد.StopAsync: هنگام بسته شدن برنامه اجرا می‌شود و وظیفه توقف صحیح سرویس را برعهده دارد.با پیاده‌سازی IHostedService، می‌توان انواع کارهای پس‌زمینه مانند پردازش صف‌ها، اجرای وظایف زمان‌بندی‌شده، یا مانیتورینگ منابع را پیاده‌سازی کرد.BackgroundService چیست؟BackgroundService یک کلاس از پیش آماده‌شده است که خود IHostedService را پیاده‌سازی می‌کند و کار برنامه‌نویس را ساده‌تر می‌کند. کافی است کلاس خود را از BackgroundService ارث‌بری دهید و متد ExecuteAsync را override کنید.مثال ساده:using Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

public class MyBackgroundService : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            Console.WriteLine($&quot;Task running at: {DateTime.Now}&quot;);
            await Task.Delay(1000, stoppingToken);
        }
    }
}
در این مثال، سرویس هر ثانیه یک پیام روی کنسول چاپ می‌کند تا زمانی که برنامه متوقف شود. BackgroundService مدیریت لغو عملیات (cancellation) و StopAsync را به‌صورت داخلی انجام می‌دهد، بنابراین توسعه‌دهنده تنها بر منطق اصلی تمرکز می‌کند.تفاوت IHostedService و BackgroundServiceویژگیIHostedServiceBackgroundServiceسطح انتزاعپایین (اینترفیس پایه)بالا (کلاس آماده با حلقه async)پیاده‌سازینیاز به نوشتن StartAsync و StopAsyncفقط کافی است ExecuteAsync را override کنیدپیچیدگیبیشتر، انعطاف‌پذیری بالاساده و مناسب اکثر کارهای پس‌زمینهمثال کاربردسرویس‌های پیچیده با منطق سفارشیاجرای وظایف زمان‌بندی‌شده، پردازش صف‌هانحوه رجیستر کردن سرویس پس‌زمینهدر فایل Program.cs یا Startup.cs کافی است سرویس را به کانتینر DI اضافه کنید:builder.Services.AddHostedService&lt;MyBackgroundService&gt;();
.NET Core به‌صورت خودکار این سرویس را هنگام شروع برنامه اجرا کرده و هنگام خاتمه برنامه متوقف می‌کند.نکات مهمسرویس پس‌زمینه باید غیرمسدودکننده باشد (از async/await استفاده شود).اگر از IHostedService مستقیم استفاده می‌کنید، مدیریت حلقه و لغو عملیات باید توسط خودتان انجام شود.BackgroundService مناسب اکثر سناریوها است و مدیریت لغو و توقف را خودکار انجام می‌دهد.سرویس‌های پس‌زمینه می‌توانند همراه با برنامه وب اجرا شوند بدون آنکه درخواست‌های HTTP را مسدود کنند.نتیجه‌گیریدر .NET Core، IHostedService و BackgroundService ابزارهای استاندارد و قوی برای اجرای کارهای پس‌زمینه هستند. استفاده از BackgroundService معمولاً ساده‌تر و کارآمدتر است، اما IHostedService انعطاف‌پذیری بیشتری برای سناریوهای پیچیده ارائه می‌دهد. انتخاب بین این دو بستگی به نیاز پروژه و پیچیدگی سرویس پس‌زمینه دارد.با درک این ابزارها، توسعه‌دهندگان می‌توانند سرویس‌های پس‌زمینه قابل اعتماد و مقیاس‌پذیر در برنامه‌های خود پیاده‌سازی کنند.سناریو: ارسال ایمیل‌های اطلاع‌رسانی کاربرانفرض کنید یک سایت فروشگاهی دارید و کاربرانی که خرید می‌کنند باید ایمیل تأیید سفارش دریافت کنند.شما نمی‌خواهید ارسال ایمیل هنگام پاسخ HTTP مسدود شود، چون ممکن است چند ثانیه طول بکشد و کاربر منتظر بماند.در این حالت، یک سرویس پس‌زمینه (Background Service) مناسب است.گام ۱: ایجاد یک صف ایمیلابتدا یک صف ساده برای نگهداری ایمیل‌ها:public class EmailQueue
{
    private readonly Queue&lt;string&gt; _emails = new();
    private readonly object _lock = new();

    public void Enqueue(string email)
    {
        lock (_lock)
        {
            _emails.Enqueue(email);
        }
    }

    public string? Dequeue()
    {
        lock (_lock)
        {
            if (_emails.Count == 0) return null;
            return _emails.Dequeue();
        }
    }
}
گام ۲: ایجاد BackgroundService برای ارسال ایمیلusing Microsoft.Extensions.Hosting;
using System;
using System.Threading;
using System.Threading.Tasks;

public class EmailSenderService : BackgroundService
{
    private readonly EmailQueue _queue;

    public EmailSenderService(EmailQueue queue)
    {
        _queue = queue;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            var email = _queue.Dequeue();
            if (email != null)
            {
                // شبیه‌سازی ارسال ایمیل
                Console.WriteLine($&quot;Sending email to: {email} at {DateTime.Now}&quot;);
                await Task.Delay(500); // زمان ارسال ایمیل
            }
            else
            {
                await Task.Delay(1000); // اگر ایمیلی نبود، 1 ثانیه صبر کن
            }
        }
    }
}
گام ۳: ثبت سرویس و صف ایمیل در DIvar builder = WebApplication.CreateBuilder(args);

builder.Services.AddSingleton&lt;EmailQueue&gt;(); // صف ایمیل
builder.Services.AddHostedService&lt;EmailSenderService&gt;(); // سرویس پس‌زمینه

var app = builder.Build();
گام ۴: اضافه کردن ایمیل به صف هنگام ثبت سفارشapp.MapPost(&quot;/order&quot;, (string userEmail, EmailQueue queue) =&gt;
{
    // ثبت سفارش در پایگاه داده (شبیه‌سازی)
    Console.WriteLine($&quot;Order received for {userEmail}&quot;);

    // اضافه کردن ایمیل به صف برای ارسال توسط BackgroundService
    queue.Enqueue(userEmail);

    return Results.Ok(&quot;Order placed successfully&quot;);
});
نتیجهکاربر سفارش خود را ثبت می‌کند.ایمیل بلافاصله به صف اضافه می‌شود.سرویس پس‌زمینه EmailSenderService ایمیل‌ها را به صورت مستقل و غیرمسدودکننده ارسال می‌کند.پاسخ HTTP سریع است و کاربر منتظر نمی‌ماند.✅ مزیت: این مدل به شما امکان می‌دهد کارهای زمان‌بر یا تکراری را در پس‌زمینه انجام دهید، بدون اینکه تجربه کاربری تحت تأثیر قرار بگیرد.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Sun, 21 Sep 2025 10:52:51 +0330</pubDate>
            </item>
                    <item>
                <title>آشنایی با Real-Time Web و روش‌های پیاده‌سازی آن در .NET Core</title>
                <link>https://virgool.io/@sh.samaneh93/%D8%A2%D8%B4%D9%86%D8%A7%DB%8C%DB%8C-%D8%A8%D8%A7-real-time-web-%D9%88-%D8%B1%D9%88%D8%B4-%D9%87%D8%A7%DB%8C-%D9%BE%DB%8C%D8%A7%D8%AF%D9%87-%D8%B3%D8%A7%D8%B2%DB%8C-%D8%A2%D9%86-%D8%AF%D8%B1-net-core-rjwb06cooo4h</link>
                <description>وب از ابتدا بر اساس پروتکل HTTP طراحی شد؛ پروتکلی که ذاتاً Request-Response است. یعنی مرورگر (کلاینت) یک درخواست ارسال میکند و سرور تنها یک پاسخ میدهد. این مدل برای بسیاری از کاربردها کافی است، اما برای اپلیکیشنهای Real-Time (مانند چت آنلاین، نوتیفیکیشن لحظهای، معاملات بورسی و …) مناسب نیست.برای حل این مسئله، طی سالها تکنیکها و فناوریهای مختلفی معرفی شدند که مسیر تکامل Real-Time Web را شکل دادند. در ادامه این روشها را توضیح میدهیم و برای هر کدام نمونه کد در ASP.NET Core و JavaScript/HTML ارائه میکنیم.۱. AJAX (Asynchronous JavaScript And XML)AJAX اولین قدم برای ارتباط ناهمگام بین مرورگر و سرور بود. این روش اجازه میدهد بدون رفرش صفحه، درخواست به سرور ارسال و پاسخ دریافت کنیم.سرور (ASP.NET Core C#)// Controllers/TimeController.cs
[ApiController]
[Route(&quot;api/[controller]&quot;)]
public class TimeController : ControllerBase
{
    [HttpGet(&quot;now&quot;)]
    public IActionResult GetTime()
    {
        return Ok(DateTime.Now.ToString(&quot;HH:mm:ss&quot;));
    }
}
کلاینت (HTML + JavaScript)&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
    &lt;button =&quot;getTime()&quot;&gt;Get Server Time&lt;/button&gt;
    &lt;p id=&quot;result&quot;&gt;&lt;/p&gt;

    
        function getTime() {
            fetch(&quot;/api/time/now&quot;)
                .then(res =&gt; res.text())
                .then(data =&gt; {
                    document.getElementById(&quot;result&quot;).innerText = &quot;Server Time: &quot; + data;
                });
        }
    
&lt;/body&gt;
&lt;/html&gt;
۲. Polling (پرسوجوی دورهای)در Polling، کلاینت در بازه های زمانی مشخص (مثلاً هر ۵ ثانیه) به سرور درخواست میزند تا ببیند داده جدید وجود دارد یا نه.سرور (ASP.NET Core C#)[ApiController]
[Route(&quot;api/[controller]&quot;)]
public class MessagesController : ControllerBase
{
    [HttpGet(&quot;poll&quot;)]
    public IActionResult Poll()
    {
        return Ok(&quot;Message: &quot; + DateTime.Now);
    }
}
کلاینت (JavaScript)// هر ۵ ثانیه یکبار درخواست میزنیم
setInterval&#40;(&#41; =&gt; {
    fetch(&quot;/api/messages/poll&quot;)
        .then(res =&gt; res.text())
        .then(data =&gt; console.log(&quot;Polling:&quot;, data));
}, 5000);
📌 مشکل این روش: حتی وقتی خبری نیست، درخواستهای مکرر باعث بار اضافی روی سرور میشوند.۳. Long Polling (پرسوجوی نگهداشتهشده)در Long Polling، کلاینت یک درخواست میزند و سرور آن را نگه میدارد تا زمانی که دادهای جدید برسد یا timeout اتفاق بیفتد. سپس کلاینت بلافاصله یک درخواست جدید باز میکند.سرور (ASP.NET Core C#)private static string _lastMessage = &quot;Hello&quot;;
private static readonly object _lock = new();

[HttpGet(&quot;longpoll&quot;)]
public async Task&lt;IActionResult&gt; LongPoll(CancellationToken cancellationToken)
{
    var currentMessage = _lastMessage;

    // تا وقتی تغییری در پیام رخ نداده، منتظر میمانیم
    while (currentMessage == _lastMessage &amp;&amp; !cancellationToken.IsCancellationRequested)
    {
        await Task.Delay(500, cancellationToken);
    }

    return Ok(_lastMessage);
}

[HttpPost(&quot;send&quot;)]
public IActionResult Send([FromForm] string message)
{
    lock (_lock)
    {
        _lastMessage = message;
    }
    return Ok(&quot;Message updated!&quot;);
}
کلاینت (JavaScript)function startLongPolling() {
    fetch(&quot;/api/messages/longpoll&quot;)
        .then(res =&gt; res.text())
        .then(data =&gt; {
            console.log(&quot;Long Polling:&quot;, data);
            startLongPolling(); // دوباره درخواست جدید
        })
        .catch(err =&gt; {
            console.error(&quot;Error:&quot;, err);
            setTimeout&#40;startLongPolling, 2000&#41;; // تلاش مجدد در صورت خطا
        });
}

startLongPolling();
📌 مزیت: نسبت به Polling ساده، بهینهتر است.📌 ایراد: همچنان overhead بالایی دارد و نسبت به WebSocket ضعیفتر است.۴. Server-Sent Events (SSE)SSE یکی از ویژگیهای HTML5 است که اجازه میدهد سرور دادهها را به صورت یکطرفه به کلاینت ارسال کند.سرور (ASP.NET Core C#)[ApiController]
[Route(&quot;api/[controller]&quot;)]
public class SseController : ControllerBase
{
    [HttpGet(&quot;stream&quot;)]
    public async Task Stream(CancellationToken cancellationToken)
    {
        Response.Headers.Add(&quot;Content-Type&quot;, &quot;text/event-stream&quot;);

        while (!cancellationToken.IsCancellationRequested)
        {
            var message = $&quot;data: Server time is {DateTime.Now}\n\n&quot;;
            var bytes = System.Text.Encoding.UTF8.GetBytes(message);

            await Response.Body.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
            await Response.Body.FlushAsync(cancellationToken);

            await Task.Delay(2000, cancellationToken);
        }
    }
}
کلاینت (HTML + JavaScript)&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
    &lt;h3&gt;Server-Sent Events Example&lt;/h3&gt;
    &lt;ul id=&quot;messages&quot;&gt;&lt;/ul&gt;

    
        const evtSource = new EventSource(&quot;/api/sse/stream&quot;);
        evtSource.onmessage = (event) =&gt; {
            const li = document.createElement(&quot;li&quot;);
            li.textContent = event.data;
            document.getElementById(&quot;messages&quot;)(li);
        };
    
&lt;/body&gt;
&lt;/html&gt;
📌 محدودیت: یکطرفه است (فقط سرور → کلاینت)، و فقط داده متنی ارسال میشود.۵. WebSocketWebSocket یک پروتکل جدید در لایه ۷ است که ارتباط دوطرفه و پایدار بین کلاینت و سرور برقرار میکند.سرور (ASP.NET Core C#)// Program.cs
var app = WebApplication.CreateBuilder(args).Build();

app.UseWebSockets();

app.Map(&quot;/ws&quot;, async context =&gt;
{
    if (context.WebSockets.IsWebSocketRequest)
    {
        var webSocket = await context.WebSockets.AcceptWebSocketAsync();
        var buffer = new byte[1024 * 4];

        while (true)
        {
            var result = await webSocket.ReceiveAsync(
                new ArraySegment&lt;byte&gt;(buffer), CancellationToken.None);

            if (result.MessageType == WebSocketMessageType.Close)
            {
                await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, &quot;&quot;, CancellationToken.None);
                break;
            }

            var msg = Encoding.UTF8.GetString(buffer, 0, result.Count);
            var response = Encoding.UTF8.GetBytes(&quot;Echo: &quot; + msg);

            await webSocket.SendAsync(
                new ArraySegment&lt;byte&gt;(response),
                WebSocketMessageType.Text,
                true,
                CancellationToken.None);
        }
    }
});

app.Run();
کلاینت (HTML + JavaScript)&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;body&gt;
    &lt;h3&gt;WebSocket Example&lt;/h3&gt;
    &lt;input id=&quot;msg&quot; type=&quot;text&quot; placeholder=&quot;Type message...&quot; /&gt;
    &lt;button =&quot;sendMessage()&quot;&gt;Send&lt;/button&gt;
    &lt;ul id=&quot;chat&quot;&gt;&lt;/ul&gt;

    
        const socket = new WebSocket(&quot;ws://localhost:5000/ws&quot;);

        socket.onmessage = (event) =&gt; {
            const li = document.createElement(&quot;li&quot;);
            li.textContent = event.data;
            document.getElementById(&quot;chat&quot;)(li);
        };

        function sendMessage() {
            const msg = document.getElementById(&quot;msg&quot;).value;
            socket.send(msg);
        }
    
&lt;/body&gt;
&lt;/html&gt;
📌 مزیت: سریعترین و بهینهترین روش برای Real-Time.۶. SignalRSignalR کتابخانه مایکروسافت است که ارتباط Real-Time را ساده میکند. SignalR به صورت خودکار بین WebSocket, SSE, Long Polling سوییچ میکند.Hub (C#)public class ChatHub : Hub
{
    public async Task SendMessage(string user, string message)
    {
        await Clients.All.SendAsync(&quot;ReceiveMessage&quot;, user, message);
    }
}
Program.csvar builder = WebApplication.CreateBuilder(args);
builder.Services.AddSignalR();

var app = builder.Build();
app.MapHub&lt;ChatHub&gt;(&quot;/chatHub&quot;);
app.Run();
کلاینت (HTML + JavaScript)&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;script &gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h3&gt;SignalR Chat Example&lt;/h3&gt;
    &lt;input id=&quot;user&quot; placeholder=&quot;User&quot; /&gt;
    &lt;input id=&quot;msg&quot; placeholder=&quot;Message&quot; /&gt;
    &lt;button =&quot;sendMessage()&quot;&gt;Send&lt;/button&gt;
    &lt;ul id=&quot;chat&quot;&gt;&lt;/ul&gt;

    
        const connection = new signalR.HubConnectionBuilder()
            .withUrl(&quot;/chatHub&quot;)
            .build();

        connection.on(&quot;ReceiveMessage&quot;, (user, message) =&gt; {
            const li = document.createElement(&quot;li&quot;);
            li.textContent = `${user}: ${message}`;
            document.getElementById(&quot;chat&quot;)(li);
        });

        connection.start().then(() =&gt; {
            console.log(&quot;Connected to SignalR&quot;);
        });

        function sendMessage() {
            const user = document.getElementById(&quot;user&quot;).value;
            const msg = document.getElementById(&quot;msg&quot;).value;
            connection.invoke(&quot;SendMessage&quot;, user, msg);
        }
    
&lt;/body&gt;
&lt;/html&gt;
✅ جمع بندی مسیر تکامل Real-Time WebAJAX → شروع ارتباط ناهمگام (Request-Response).Polling → پرسوجوی دورهای، ساده اما پرهزینه.Long Polling → نگه داشتن درخواست تا رسیدن داده جدید.SSE → ارتباط یکطرفه سرور → کلاینت، فقط متنی.WebSocket → ارتباط دوطرفه و پایدار.SignalR → لایه انتزاعی در .NET که بهترین روش را انتخاب میکند.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Sun, 07 Sep 2025 09:46:31 +0330</pubDate>
            </item>
                    <item>
                <title>آموزش استفاده از HttpClient در C# و .NET</title>
                <link>https://virgool.io/@sh.samaneh93/%D8%A2%D9%85%D9%88%D8%B2%D8%B4-%D8%A7%D8%B3%D8%AA%D9%81%D8%A7%D8%AF%D9%87-%D8%A7%D8%B2-httpclient-%D8%AF%D8%B1-c-%D9%88-net-oox12omzhfmq</link>
                <description>در C# و .NET، کلاس HttpClient یکی از ابزارهای اصلی برای ارسال درخواست‌های HTTP و دریافت پاسخ‌ها از سرورها است. وقتی می‌خواهید از برنامه خود با یک وب‌سرویس (API) یا یک وب‌سایت ارتباط برقرار کنید، HttpClient به شما این امکان را می‌دهد.ویژگی‌های مهم HttpClientارسال درخواست‌ها: GET, POST, PUT, DELETE و غیره.دریافت پاسخ‌ها: شامل محتوای HTML، JSON، XML یا فایل‌ها.پشتیبانی از async/await: عملیات شبکه به صورت غیرهمزمان انجام می‌شود و برنامه بلوکه نمی‌شود.مدیریت هدرها و کوکی‌ها: امکان شخصی‌سازی درخواست‌ها و مدیریت زمان‌بندی.1️⃣ استفاده مستقیم از HttpClientpublic class PostsController : ControllerBase
{
    [HttpGet]
    public async Task&lt;IActionResult&gt; GetAll()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri(&quot;https://jsonplaceholder.typicode.com/&quot;);
            var result = await client.GetStringAsync(&quot;/posts&quot;);
            var finalResult = JsonConvert.DeserializeObject&lt;List&lt;Post&gt;&gt;(result);
            return Ok(finalResult);
        }
    }
}
✅ مزیت: ساده و مستقیم⚠️ نکته: ایجاد HttpClient در هر درخواست می‌تواند منابع را هدر دهد و باعث مشکلات اتصال شود.2️⃣ استفاده از Named Clientدر Program.cs:builder.Services.AddHttpClient(&quot;posts&quot;, client =&gt;
{
    client.BaseAddress = new Uri(&quot;https://jsonplaceholder.typicode.com/&quot;);
});
در کنترلر:public class PostsController : ControllerBase
{
    private readonly IHttpClientFactory _httpClientFactory;

    public PostsController(IHttpClientFactory httpClientFactory)
    {
        _httpClientFactory = httpClientFactory;
    }

    [HttpGet]
    public async Task&lt;IActionResult&gt; GetAll()
    {
        using (var client = _httpClientFactory.CreateClient(&quot;posts&quot;))
        {
            var result = await client.GetStringAsync(&quot;/posts&quot;);
            var finalResult = JsonConvert.DeserializeObject&lt;List&lt;Post&gt;&gt;(result);
            return Ok(finalResult);
        }
    }
}
✅ مزیت: مدیریت بهتر منابع و قابلیت استفاده مجدد از HttpClient3️⃣ استفاده از Typed Clientدر Program.cs:builder.Services.AddHttpClient&lt;PostService&gt;()
       .AddHttpMessageHandler&lt;LogHttpRequest&gt;();
ایجاد کلاس PostService:public class PostService
{
    private readonly HttpClient _httpClient;

    public PostService(HttpClient httpClient)
    {
        _httpClient = httpClient;
        _httpClient.BaseAddress = new Uri(&quot;https://jsonplaceholder.typicode.com/&quot;);
    }

    public async Task&lt;List&lt;Post&gt;&gt; GetAll()
    {
        var stringResult = await _httpClient.GetStringAsync(&quot;/posts&quot;);
        return JsonConvert.DeserializeObject&lt;List&lt;Post&gt;&gt;(stringResult);
    }
}
در کنترلر:public class PostsTypedController : ControllerBase
{
    private readonly PostService _postService;

    public PostsTypedController(PostService postService)
    {
        _postService = postService;
    }

    [HttpGet]
    public async Task&lt;IActionResult&gt; GetAll()
    {
        return Ok(await _postService.GetAll());
    }
}
✅ مزیت: جداسازی منطق HTTP و سرویس‌دهی، قابلیت تست و نگهداری بهتر.💡 جمع‌بندی:برای پروژه‌های کوچک و سریع، استفاده مستقیم کافی است.برای پروژه‌های بزرگ و مقیاس‌پذیر، بهتر است از Named یا Typed Client استفاده کنید تا مدیریت منابع و نگهداری آسان‌تر شود.</description>
                <category>سمانه شریفی</category>
                <author>سمانه شریفی</author>
                <pubDate>Sun, 31 Aug 2025 17:37:15 +0330</pubDate>
            </item>
            </channel>
</rss>