es
Feedback
Developer Advocate

Developer Advocate

Ir al canal en Telegram
Buy Ad
1 035
Suscriptores
Sin datos24 horas
Sin datos7 días
-130 días
Archivo de publicaciones
در دنیای توسعه نرم‌افزار، تست‌های واحد (Unit Tests) به عنوان یکی از مهم‌ترین ارکان حفظ کیفیت و پایداری نرم‌افزار شناخته می‌شوند. اما چه چیزی یک تست واحد را واقعاً مؤثر و کارآمد می‌کند؟ در اینجا به برخی ویژگی‌های کلیدی یک تست واحد خوب می‌پردازیم: 1. سریع (Fast): تست‌های واحد باید به سرعت اجرا شوند. زمان اجرای کوتاه تست‌ها به توسعه‌دهندگان امکان می‌دهد به راحتی و به سرعت بازخورد بگیرند و بیشتر بر روی کد تمرکز کنند. یک تست سریع، اجرای پی‌درپی را امکان‌پذیر می‌سازد، که برای یکپارچه‌سازی مستمر (CI) بسیار حیاتی است. 2. ایزوله (Isolated): یک تست واحد باید مستقل از سایر تست‌ها باشد. این به معنای عدم وابستگی به وضعیت یا داده‌های تست‌های دیگر است. برای حفظ ایزولاسیون، می‌توان از استاب‌ها یا موک‌ها استفاده کرد. این ویژگی کمک می‌کند تا علت شکست تست‌ها به راحتی تشخیص داده شود. 3. خوانا (Readable): تست‌ها باید به گونه‌ای نوشته شوند که به راحتی قابل درک باشند. نام‌گذاری صحیح، توضیحات مختصر و واضح، و استفاده از کنوانسیون‌های نام‌گذاری استاندارد به خوانایی تست‌ها کمک می‌کند. تلاش کنید تا تست‌های شما به نوعی سند برای نحوه عملکرد کد باشند. 4. تکرارپذیر (Repeatable): یک تست خوب هر زمان که اجرا شود، باید نتایج مشابهی تولید کند. برای تضمین این ویژگی، نباید هیچگونه وابستگی به منابع خارجی مثل پایگاه داده‌های زنده یا API‌های خارجی داشته باشید. 5. مستقل از محیط (Environment-Independent): یک تست واحد نباید تحت تأثیر تغییرات محیطی مثل تغییرات منطقه زمانی، تنظیمات سیا‌محلی (Locale)، یا پیکربندی سیستم قرار بگیرد. این ویژگی به پایداری و دقت تست‌ها کمک می‌کند. 6. توصیفی (Descriptive): در صورت شکست، تست باید اطلاعات کافی برای تشخیص مشکل را فراهم کند. پیام‌های خطای مناسب و استفاده از Assertهای درست به تحلیل سریع مشکلات کمک می‌کند. در نهایت، اگر بخواهیم تمام ویژگی‌های بالا را در یک نمونه ساده از تست واحد پیاده‌سازی کنیم، کدی مانند زیر می‌تواند شروع خوبی باشد:
[Test]
public void CalculateTotalPrice_WhenItemsAreAdded_ShouldReturnCorrectSum()
{
    // Arrange
    var cart = new ShoppingCart();
    cart.AddItem(new Item { Price = 10 });
    cart.AddItem(new Item { Price = 20 });
    
    // Act
    var totalPrice = cart.CalculateTotalPrice();
    
    // Assert
    Assert.AreEqual(30, totalPrice, "Total price calculation is incorrect.");
}
توجه داشته باشید که این تست به هیچ منبع خارجی وابسته نیست، سریع و ایزوله است، و در صورت شکست دلایل مشخصی ارائه می‌دهد. @DeveloperAdvocate 🥑

بحث برنامه‌نویسی ناهمگام در #CSharp نباید به async/await محدود شود. ابزارها و امکانات قدرتمندی مانند IAsyncEnumerable و ValueTask وجود دارند که می‌توانند عملکرد و کارایی کد شما را به طور چشمگیری بهبود بخشند. ### IAsyncEnumerable IAsyncEnumerable نوعی از collectionهای قابل پیمایش است که به صورت غیرهمزمان می‌تواند عناصر را بازگرداند. این نوع به‌ خصوص زمان‌هایی که نیاز به پردازش جریانی از داده‌ها دارید که به‌طور ناهمگام تولید می‌شود و نیازی به بارگذاری تمامی داده‌ها در حافظه به‌طور یکجا ندارید، بسیار مفید است. این توانایی می‌تواند حافظه استفاده شده توسط برنامه را تا حد زیادی کاهش دهد.
public async IAsyncEnumerable<int> FetchDataAsyncEnumerable()
{
    for (int i = 0; i < 10; i++)
    {
        await Task.Delay(1000); // شبیه‌سازی تاخیر شبکه
        yield return i;
    }
}

// استفاده از IAsyncEnumerable
await foreach (var number in FetchDataAsyncEnumerable())
{
    Console.WriteLine(number);
}
### ValueTask ValueTask ساختاریست که عملکردی مشابه Task دارد اما برای بالابردن کارایی در سناریوهایی که نتیجه فوراً در دسترس است یا نیازی به شروع یک عملیات ناهمگام جدید نیست طراحی شده است. استفاده از ValueTask می‌تواند هزینه‌های اضافی تخصیص حافظه را کاهش دهد، به‌ویژه در سناریوهای با فراخوانی‌های مکرر.
public ValueTask<int> GetQuickResultAsync()
{
    // زمانی که می‌دانیم نتیجه فوراً در دسترس است
    if (condition)
    {
        return new ValueTask<int>(42);
    }
    else
    {
        return new ValueTask<int>(LongRunningOperation());
    }
}
در استفاده از ValueTask باید احتیاط کنید، زیرا استفاده نادرست می‌تواند منجر به رفتارهای نامطلوب و کاهش کارایی شود. تنها در زمانی که واقعاً نیازمند بهینه‌سازی هستید، و مزایا دقیقاً مشخص است، از ValueTask استفاده کنید. با استفاده مناسب از این ابزارها، می‌توانید کدهاتان را هم بهبودیافته‌تر و هم بهینه‌تر کنید. در برنامه‌ریزی برای پیاده‌سازی سیستم‌های بزرگ، داشتن درک عمیق از این مفاهیم قطعاً ابزار قدرتمندی در اختیار شما قرار خواهد داد. @DeveloperAdvocate 🥑

در دنیای دیتابیس و به‌ویژه EF Core، کنترل همزمانی یکی از چالش‌های مهم است. دو رویکرد اصلی برای مدیریت این موضوع داریم: کنترل همزمانی خوش‌بینانه (Optimistic Concurrency) و کنترل همزمانی بدبینانه (Pessimistic Concurrency). در این پست به تفاوت این دو و نحوه پیاده‌سازی آنها در EF Core می‌پردازیم. کنترل همزمانی خوش‌بینانه: در این روش، عملیات خواندن بدون قفل انجام می‌شود. فرض بر این است که تصادم همزمانی کم است و چک نهایی در زمان ذخیره‌سازی انجام می‌شود. این رویکرد برای سیستم‌هایی مناسب است که دسترسی به داده‌ها بیشتر از تغییرات آن است. برای پیاده‌سازی این رویکرد در EF Core، می‌توان از فیلد ردیابی نسخه مانند RowVersion استفاده کرد. این فیلد هنگام ذخیره‌سازی به‌روزرسانی می‌شود تا مطمئن شود که هیچ‌کس دیگری داده را بعد از آخرین خواندن تغییر نداده است.
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    [Timestamp]
    public byte[] RowVersion { get; set; }
}

// برای ذخیره‌سازی
using (var context = new ApplicationDbContext())
{
    var product = await context.Products
        .FirstOrDefaultAsync(p => p.Id == productId);
    
    product.Price = newPrice;

    try
    {
        await context.SaveChangesAsync();
    }
    catch (DbUpdateConcurrencyException)
    {
        // برخورد همزمانی بین دیتا اتفاق افتاده است
    }
}
کنترل همزمانی بدبینانه: در این روش، فرض بر این است که تصادم همزمانی بالا است. بنابراین، با استفاده از قفل‌ها کنترل می‌شود که تنها یک تراکنش بتواند داده‌ها را تغییر دهد. این رویکرد برای سیستم‌هایی مناسب است که تغییرات زیادی بر داده‌ها اعمال می‌شود و امکان تصادم بالا است. در EF Core می‌توانید از صفت WithLock در کوئری‌ها استفاده کنید تا قفل ببندید.
using (var transaction = context.Database.BeginTransaction())
{
    var product = await context.Products
        .FromSqlRaw("SELECT * FROM Products WITH (UPDLOCK) WHERE Id = {0}", productId)
        .FirstOrDefaultAsync();
    
    product.Price = newPrice;

    await context.SaveChangesAsync();
    transaction.Commit();
}
هر دو رویکرد مزایا و معایب خاص خود را دارند و انتخاب بین آنها بستگی به سناریوی خاص شما دارد. به دقت نوع بار کاری که برنامه‌تان با آن مواجه است و خطر برخورد همزمانی را بررسی کنید تا بهترین روش را انتخاب کنید. @DeveloperAdvocate 🥑

Dependency Confusion یک نوع حمله‌ی امنیتی است که از تفاوت‌های مدیریت وابستگی میان ریجستری‌های عمومی و خصوصی بهره‌برداری می‌کند. این تهدید زمانی اتفاق می‌افتد که نرم‌افزاری به طور ناآگاهانه کتابخانه‌ای از یک ریجستری عمومی به جای ریجستری خصوصی خود دریافت کند، که ممکن است شامل کد مخربی باشد. برای محافظت در برابر این نوع حملات در پروژه‌های دات‌نت، می‌توانید از تکنیک‌های زیر استفاده کنید: 1. فهرست اولویت‌بندی منابع: در فایل nuget.config، مطمئن شوید که منابع ریجستری خصوصی قبل از منابع عمومی تعریف شده‌اند. به این ترتیب، اگر یک بسته با همان نام در ریجستری خصوصی وجود داشته باشد، همیشه از آنجا دریافت می‌شود. 2. استفاده از PackageSigning: از ویژگی امضای بسته‌ها در NuGet برای تضمین صحت و ایمنی بسته‌ها استفاده کنید. این کار به شما این امکان را می‌دهد که مطمئن شوید بسته‌ها از منابع معتبری تهیه شده‌اند. 3. مانیتورینگ دقیق: بسته‌های موجود در ریجستری‌های عمومی را به دقت بررسی و مانیتور کنید؛ به خصوص وقتی که نام آن‌ها مشابه نام‌های داخلی است. 4. تعیین نسخه‌های مشخص: همیشه نسخه‌های مشخصی از بسته‌ها را در فایل‌های پروژه خود تعیین کنید تا از به‌کارگیری نسخه‌های جدید و غیرمنتظره جلوگیری شود. بهتر است همیشه جریان وابستگی‌هایتان را کنترل کنید و از ابزارهای امنیتی که می‌توانند این نوع فعالیت‌ها را مانیتور کنند، بهره ببرید. از آنجا که امنیت در لایه‌های مختلفی اجرا می‌شود، یکپارچگی و توانایی تشخیص به موقع می‌توانند تأثیر بزرگی بر جلوگیری از خطرات محتمل داشته باشند. @DeveloperAdvocate 🥑

در دنیای طراحی مبتنی بر دامنه (DDD)، یکی از مفاهیم کلیدی و بسیار ضروری، "Bounded Context" است. منظور از Bounded Context، یک مرز یا محدوده است که در آن یک مدل واحد وجود دارد که مفاهیم دامنه را تعریف و پیاده‌سازی می‌کند. این مفهوم به ما امکان می‌دهد تا مدل‌های مختلفی برای بخش‌های متفاوت از سیستم داشته باشیم که به صورت مستقل و بدون تداخل با یکدیگر توسعه یابند. برای درک بهتر این مفهوم، به یک مثال عملی توجه کنید: فرض کنید در حال توسعه یک سیستم تجارت الکترونیک هستیم که دارای دو قسمت اصلی است: مدیریت مشتریان و مدیریت سفارشات. هر یک از این بخش‌ها می‌تواند یک Bounded Context مجزا باشد. در Bounded Context مدیریت مشتریان، تمرکز بر روی اطلاعات فردی مشتریان، مانند نام، آدرس‌ها و اولویت‌های آنهاست. این بخش ممکن است از کلاس‌های و موجودیت‌های خاص خود برای مدیریت داده‌ها و عملیات مربوط به مشتریان استفاده کند. در مقابل، Bounded Context مدیریت سفارشات به جزئیات سفارش‌ها، از جمله لیست محصولات سفارش داده شده، تاریخ تحویل و وضعیت پرداخت توجه می‌کند. این بخش نیز می‌تواند مدل و موجودیت‌های مختص خود را داشته باشد. به دلیل جدایی این دو Bounded Context، می‌توانیم تغییرات و بهبودهای لازم را در هر بخش به صورت مستقل و بدون نگرانی از تأثیرات جانبی بر بخش دیگر اعمال کنیم. یک مثال ساده از کلاسی در Bounded Context مدیریت مشتریان به این شکل می‌تواند باشد:
namespace CustomerManagementContext
{
    public class Customer
    {
        public Guid Id { get; private set; }
        public string Name { get; private set; }
        public string Email { get; private set; }

        public Customer(Guid id, string name, string email)
        {
            Id = id;
            Name = name;
            Email = email;
        }

        public void UpdateEmail(string newEmail)
        {
            // Validate and update logic
            Email = newEmail;
        }
    }
}
در اینجا کلاس Customer تنها به جزئیات مربوط به مشتریان می‌پردازد و هیچ اطلاعی از مدل سفارشات ندارد. این جدا‌سازی به ما کمک می‌کند که سیستم‌های بزرگ را به بخش‌های کوچک‌تر و قابل مدیریت‌تر تقسیم کنیم، که به نوبه خود توسعه و نگهداری را ساده‌تر و موثرتر می‌کند. @DeveloperAdvocate 🥑

در دنیای مدرن توسعه نرم‌افزار، استفاده از الگوی Delegate و Event در زبان #C هنوز هم پایه بسیاری از مفاهیم برنامه‌نویسی رویدادگرا است. در این مثال، راهی برای ایجاد یک سیستم ساده که به روزرسانی قیمت محصولات را مدیریت می‌کند، خواهیم دید. این سیستم شامل یک کلاس Publisher برای انتشار رویدادها و یک کلاس Subscriber برای گوش دادن به این رویدادها خواهد بود.
using System;

// تعریف رویداد بر اساس Delegate برای بروزرسانی قیمت
public delegate void PriceUpdatedEventHandler(object sender, PriceUpdatedEventArgs e);

// کلاس حامل اطلاعات رویداد
public class PriceUpdatedEventArgs : EventArgs
{
    public string ProductName { get; }
    public decimal NewPrice { get; }

    public PriceUpdatedEventArgs(string productName, decimal newPrice)
    {
        ProductName = productName;
        NewPrice = newPrice;
    }
}

// کلاس منتشر کننده رویداد
public class PricePublisher
{
    // تعریف رویداد
    public event PriceUpdatedEventHandler PriceUpdated;

    public void UpdatePrice(string productName, decimal newPrice)
    {
        Console.WriteLine($"Updating price of {productName} to {newPrice}...");
        OnPriceUpdated(new PriceUpdatedEventArgs(productName, newPrice));
    }

    protected virtual void OnPriceUpdated(PriceUpdatedEventArgs e)
    {
        // انتشار رویداد
        PriceUpdated?.Invoke(this, e);
    }
}

// کلاس شنونده رویداد
public class PriceSubscriber
{
    public void OnPriceUpdated(object sender, PriceUpdatedEventArgs e)
    {
        Console.WriteLine($"Received update: Product {e.ProductName} has new price {e.NewPrice}");
    }
}

class Program
{
    static void Main()
    {
        var publisher = new PricePublisher();
        var subscriber = new PriceSubscriber();

        // مشترک شدن به رویداد
        publisher.PriceUpdated += subscriber.OnPriceUpdated;

        // بروزرسانی قیمت برای راه‌اندازی رویداد
        publisher.UpdatePrice("Laptop", 999.99m);
        publisher.UpdatePrice("Smartphone", 699.99m);
    }
}
در این مثال، کلاس PricePublisher که مسئول انتشار رویداد است، دارای یک متد UpdatePrice است که هنگام بروزرسانی قیمت محصول یک رویداد Trigger می‌کند. این رویداد به کمک Delegate PriceUpdatedEventHandler تعریف شده و اطلاعات مربوط به رویداد در کلاس PriceUpdatedEventArgs حمل می‌شود. کلاس PriceSubscriber به این رویداد گوش می‌دهد و عملکرد مشخصی هنگام وقوع رویداد اجرا می‌کند. امیدوارم این مثال الهام‌بخش جهت استفاده از Delegates و Events در پروژه‌های پیشرفته‌تر شما باشد. @DeveloperAdvocate 🥑

🔍 تفاوت‌ها بین بازخورد سبک و بازخورد معماری در یک پول ریکوئست، مفاهیمی کلیدی در ارتقاء کیفیت کد و توسعه مستمر نرم‌افزار هستند. بیایید به این دو جنبه مهم با دید دقیق نگاه کنیم: 1. بازخورد سبک: این نوع بازخورد بر جزئیات کوچکتری مانند ساختار کد، فرمت بندی، نامگذاری متغیرها، و کنوانسیون‌های کدنویسی تمرکز دارد. هدف اصلی از این بازخورد بهبود قابلیت خوانایی و همگام‌سازی کد با استانداردهای تیم است. برای مثال:
    // نظر: نام متغیر بهتر است توصیفی باشد
    string dt = DateTime.Now.ToString("yyyyMMdd"); // بهبود یافته
    string currentDate = DateTime.Now.ToString("yyyyMMdd");
    
2. بازخورد معماری: برخلاف بازخورد سبک، بازخورد معماری به مفهوم و ساختار کلی برنامه می‌پردازد و نحوه تعامل اجزاء مختلف سیستم با یکدیگر را بررسی می‌کند. این بازخورد ممکن است مسائل بسیار بزرگی را شامل شود، مانند جدا کردن لایه‌های برنامه، الگوهای طراحی، یا مقیاس‌پذیری و کارایی سرویس‌ها. برای مثال:
    // نظر: در نظر گرفتن استفاده از الگوی Repository برای جداسازی منطق دسترسی به داده‌ها
    public class UserRepository : IUserRepository
    {
        private readonly DbContext _context;

        public UserRepository(DbContext context)
        {
            _context = context;
        }

        public IEnumerable<User> GetAllUsers()
        {
            // منطق دسترسی به داده‌ها
        }
    }
    
در جلسات بازنگری کد، تمایز قائل شدن بین این دو نوع بازخورد بسیار مهم است تا بتوان الویت‌های مناسب را تعیین کرد و تمرکز تیم را بر بهبود مستمر و ارتقاء کلی ساختاری سیستم حفظ کرد. 📈🌟 @DeveloperAdvocate 🥑

توسعه‌دهنده‌های عزیز و معماران نرم‌افزار، امروز قصد داریم یکی از ویژگی‌های جدید .NET 10 Preview 3 را بررسی کنیم که می‌تواند کدنویسی شما را ارتقا دهد: پیشرفت‌های جدید در سرورهای HTTP/3. HTTP/3، با استفاده از پروتکل QUIC، به شما امکانات جدیدی برای بهینه‌سازی عملکرد شبکه می‌دهد و بهبود چشمگیری در تأخیر ارتباطات فراهم می‌کند. در .NET 10 Preview 3، مایکروسافت چندین بهبود برای پشتیبانی از HTTP/3 اضافه کرده که قابل توجه هستند. در کد زیر، به نحوه‌ی پیکربندی یک سرور با استفاده از Kestrel نگاه کنید تا ارتباطات HTTP/3 را پشتیبانی کند:
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.ConfigureKestrel(serverOptions =>
                {
                    serverOptions.ListenAnyIP(5000, listenOptions =>
                    {
                        listenOptions.UseHttps(); // پشتیبانی از HTTPS الزامی است
                        listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http3;
                    });
                });

                webBuilder.UseStartup<Startup>();
            });
}
این مثال نشان می‌دهد که چگونه می‌توانید به راحتی پروتکل HTTP/3 را روی سرور خود فعال کنید. با انجام این تنظیمات، می‌توان انتظار داشت که عملکرد سرور در شرایط شبکه پرچالش بهبود یابد. اگر در حال توسعه نرم‌افزارهایی هستید که نیاز به کارایی شبکه بالا دارند، توصیه می‌کنیم که قابلیت‌های HTTP/3 در .NET 10 Preview 3 را بررسی کنید و از آن بهره ببرید. این امکانات می‌توانند تجربه کاربری نرم‌افزار شما را به سطح جدیدی ارتقا دهند. آیا آماده‌اید که سرویس‌های خود را با سرعت و کارایی دستگاه‌های امروزی همگام کنید؟ منتظر نظرات ارزشمندتان هستیم! @DeveloperAdvocate 🥑

در دنیای تکنولوژی اصطلاحات احراز هویت (Authentication) و مجوز دسترسی (Authorization) اغلب در کنار یکدیگر می‌آیند ولی نباید با هم اشتباه گرفته شوند. برای توضیح این مفاهیم، بیایید از یک تشبیه ساده استفاده کنیم و سپس به جزئیات تکنیکی آن بپردازیم. تشبیه: تصور کنید شما به یک کلوب شبانه وارد می‌شوید. در ورودی، نگهبان از شما کارت شناسایی می‌خواهد. این فرآیند مانند احراز هویت است: «آیا شما واقعاً کی هستید که ادعا می‌کنید؟» حالا بعد از تأیید هویت شما، می‌توانید وارد کلوب شوید، اما نمی‌توانید به همه مناطق دسترسی داشته باشید. مثلاً، ممکن است به منطقه VIP اجازه ورود نداشته باشید. این مرحله مانند مجوز دسترسی است: «شما به کدام بخش‌ها دسترسی دارید؟» توضیح تکنیکی: در دنیای نرم‌افزار، احراز هویت فرآیندی است که در آن کاربر، مشتری، یا سرویس باید هویت خود را اثبات کنند. این کار معمولاً از طریق ترکیب نام کاربری و رمز عبور یا توکن‌های OAuth انجام می‌شود.
public class AuthenticationService
{
    public bool AuthenticateUser(string username, string password)
    {
        // Check the username and password against stored credentials
        return this.CheckCredentials(username, password);
    }

    private bool CheckCredentials(string username, string password)
    {
        // In a real application, this would query a user store
        return username == "user" && password == "password";
    }
}
مجوز دسترسی فرآیندی است که بعد از احراز هویت اتفاق می‌افتد و تصمیم می‌گیرد که آیا کاربر به منابع و عملیات خاصی دسترسی دارد یا خیر. اغلب این کار با استفاده از نقش‌ها (roles) و سیاست‌ها (policies) انجام می‌شود.
public class AuthorizationService
{
    public bool AuthorizeUser(string username, string role)
    {
        // Check if the user has the appropriate role
        return this.CheckUserRole(username, role);
    }

    private bool CheckUserRole(string username, string role)
    {
        // In a real application, this would query a user roles store
        return username == "user" && role == "admin";
    }
}
به بیان ساده، احراز هویت می‌پرسد: «شما کی هستید؟» و مجوز دسترسی بررسی می‌کند: «چه کاری می‌توانید انجام دهید؟». فهم صحیح و به کارگیری مناسب این مفاهیم برای طراحی سیستم‌های امن و کارا ضروری است. @DeveloperAdvocate 🥑

🌟 استفاده از Dapper برای کوئری‌های حساس به عملکرد در برنامه‌هایی که از EF Core استفاده می‌کنند در برنامه‌های تحت NET. که عمدتاً از EF Core برای دسترسی به داده‌ها استفاده می‌کنند، مواقعی وجود دارد که نیاز به کوئری‌های حساس به عملکرد داریم. استفاده از Dapper، یک میکرو ORM سبک‌وزن و سریع، در چنین مواقعی می‌تواند انتخابی عالی باشد. در ادامه، نحوه استفاده از Dapper در کنار EF Core برای اجرای کوئری‌های خاص و بهینه‌سازی شده را بررسی می‌کنیم: فرض کنیم شما یک موجودیت ساده به نام Product دارید:
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
}
ابتدا، اگر از EF Core استفاده می‌کنید، Context دیتابیس خود را همچنان به مانند سابق تعریف کنید:
public class MyDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("your_connection_string");
    }
}
اکنون برای استفاده از Dapper، شما به یک اتصال مستقیم به پایگاه داده نیاز دارید. با نگه داشتن ارتباط EF Core و ایجاد یک مقداری از DbConnection، می‌توانید به راحتی از قدرت Dapper استفاده کنید:
using (var context = new MyDbContext())
{
    // دریافت اتصال از EF Core
    var connection = context.Database.GetDbConnection();
    
    // باز کردن اتصال (در صورت بسته بودن)
    if (connection.State == ConnectionState.Closed)
    {
        connection.Open();
    }

    // اجرای یک کوئری سریع با Dapper
    var sql = "SELECT * FROM Products WHERE Price > @PriceLimit";
    var products = await connection.QueryAsync<Product>(sql, new { PriceLimit = 100 });
    
    foreach (var product in products)
    {
        Console.WriteLine($"Product Name: {product.Name}, Price: {product.Price}");
    }
}
این ترکیب به شما اجازه می‌دهد تا از امکانات EF Core برای مدیریت تغییرات داده و مهاجرت‌های پایگاه داده استفاده کنید، در حالی که برای کوئری‌های خاص و بهینه شده به قدرت و سرعت Dapper تکیه کنید. نکته اصلی این است که بدانید در هر شرایطی از بهترین ابزار استفاده کنید تا عملکرد و قابلیت نگهداری کدها بهینه باشد. 🛠️ @DeveloperAdvocate 🥑

Circuit Breaker Policy Fine-tuning Best Practice Summary of some best practice and insights about circuit breaker resilience policy fine-tuning. The post Circuit Breaker Policy Fine-tuning Best Practice appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/circuit-breaker-policy-finetuning-best-practice/ #.NET,#C#,#CircuitBreaker,#Polly,#resilience @DeveloperAdvocate 🥑

Announcing dotnet run app.cs – A simpler way to start with C# and .NET 10 We are super excited to introduce a new feature that was released as part of .NET 10 Preview 4 that makes getting started with C# easier than ever. You can now run a C# file directly using dotnet run app.cs. This means you no longer need to create a project file or scaffold a whole … The post Announcing dotnet run app.cs – A simpler way to start with C# and .NET 10 appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/announcing-dotnet-run-app/ #.NET,#.NET10,#Featured @DeveloperAdvocate 🥑

Fine-tune the volume of logs your app produces Explores the new log sampling feature The post Fine-tune the volume of logs your app produces appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/finetune-the-volume-of-logs-your-app-produces/ #.NET,#.NETFundamentals,#.NET8,#logging @DeveloperAdvocate 🥑

Using AI Foundry with .NET MAUI Using AI Foundry with .NET MAUI brings the power of LLMs to mobile and desktop applications. The post Using AI Foundry with .NET MAUI appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/using-ai-foundry-with-dotnet-maui/ #.NET,#.NETMAUI,#AI,#C#,#MEAI @DeveloperAdvocate 🥑

Catch Up on Microsoft Build 2025: Essential Sessions for .NET Developers Get up to date on all of the .NET sessions from Microsoft Build 2025 covering .NET 10, C# 14, .NET Aspire, ASP.NET Core, Blazor, AI development, and more! The post Catch Up on Microsoft Build 2025: Essential Sessions for .NET Developers appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/catching-up-on-microsoft-build-2025-essential-sessions-for-dotnet-developers/ #.NET,#AI,#ASP.NETCore,#Blazor,#C#,#CloudNative,#VisualStudioCode,#.NET10,#C#14,#GitHubCopilot,#microsoftbuild,#microsoftbuild2025 @DeveloperAdvocate 🥑

Emit logs on-demand with log buffering Learn how to delay log emission with the new log buffering feature for more intelligent, context-aware logging in .NET 9 The post Emit logs on-demand with log buffering appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/emit-logs-on-demand-with-log-buffering/ #.NET,#.NETFundamentals,#.NET9,#logging,#Observability @DeveloperAdvocate 🥑

.NET 10 Preview 5 is now available! Find out about the new features in .NET 10 Preview 5 across the .NET runtime, SDK, libraries, ASP.NET Core, Blazor, C#, .NET MAUI, and more! The post .NET 10 Preview 5 is now available! appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/dotnet-10-preview-5/ #.NET,#.NETMAUI,#ASP.NETCore,#Blazor,#C#,#.NET10,#Featured @DeveloperAdvocate 🥑

.NET and .NET Framework June 2025 servicing releases updates A recap of the latest servicing updates for .NET and .NET Framework for June 2025. The post .NET and .NET Framework June 2025 servicing releases updates appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/dotnet-and-dotnet-framework-june-2025-servicing-updates/ #.NET,#.NETFramework,#Maintenance&Updates,#.netframework @DeveloperAdvocate 🥑

Multimodal Voice Intelligence with .NET MAUI Learn how to enhance your .NET MAUI apps with multimodal AI capabilities, enabling users to interact through voice using plugins and Microsoft.Extensions.AI. The post Multimodal Voice Intelligence with .NET MAUI appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/multimodal-voice-intelligence-with-dotnet-maui/ #.NET,#.NETMAUI,#AI,#.netmaui,#aifoundry,#copilot,#speech-to-text @DeveloperAdvocate 🥑

Improve Your Productivity with New GitHub Copilot Features for .NET! We recently introduced several new GitHub Copilot-powered .NET experiences designed to help you be more productive. Take a look! The post Improve Your Productivity with New GitHub Copilot Features for .NET! appeared first on .NET Blog. Link👇🏻👇🏻👇🏻👇🏻 https://devblogs.microsoft.com/dotnet/improve-productivity-with-github-copilot-dotnet/ #.NET,#AI,#C#,#VisualStudio,#VisualStudioCode,#dotnet,#GitHubCopilot,#visualstudio,#VSCode @DeveloperAdvocate 🥑