Dependency Injection تمیز در ASP.NET Core برای تستپذیری بهتر ⚙️
یکی از مهمترین قدمها برای Clean Code در پروژههای ASP.NET Core این است که وابستگیها را مستقیم new نکنیم، بلکه از Dependency Injection استفاده کنیم. این کار هم کد را تمیزتر میکند، هم تستپذیری و امکان تغییر پیادهسازیها را بالا میبرد. 💡
فرض کنید در یک Web API کنترلری دارید که مستقیم وابسته به Service است:
این طراحی چند مشکل جدی دارد:
• کنترلر مستقیماً به
• تست Unit برای کنترلر سخت است، چون نمیتوان Mock تزریق کرد.
• در آینده اگر سرویس عوض شود (مثلاً کش اضافه شود)، باید خود کنترلر را تغییر بدهید.
راه تمیزتر این است که یک Interface تعریف کنید و آن را از DI Container تزریق کنید:
حالا کنترلر فقط Interface را میشناسد:
و در
مزیتها 🧩
• تستپذیری بالا: در تستها میتوان یک
• پیادهسازی قابلتعویض: بدون تغییر کنترلر میتوانید
• رعایت اصل D از SOLID (Dependency Inversion): وابستگی به Abstraction نه Concrete Class.
برای مطالعه بیشتر، مستندات رسمی مایکروسافت درباره DI در ASP.NET Core خیلی شفاف و بهروز است:
Microsoft Learn - Dependency injection in ASP.NET Core
قدمبهقدم اگر وابستگیهای مستقیم را به شکل Interface + DI تبدیل کنید، معماری اپلیکیشن تمیزتر، منعطفتر و آمادهٔ رشد میشود. 🚀
🔖 #CSharp #سی_شارپ #C# #_NET #ASP_NET_Core #Dependency_Injection #SOLID #Clean_Code
👤 Developix
💎 Channel: @DevelopixCSharp
یکی از مهمترین قدمها برای Clean Code در پروژههای ASP.NET Core این است که وابستگیها را مستقیم new نکنیم، بلکه از Dependency Injection استفاده کنیم. این کار هم کد را تمیزتر میکند، هم تستپذیری و امکان تغییر پیادهسازیها را بالا میبرد. 💡
فرض کنید در یک Web API کنترلری دارید که مستقیم وابسته به Service است:
public class OrdersController : ControllerBase
{
private readonly OrderService _orderService;
public OrdersController()
{
_orderService = new OrderService();
}
[HttpGet("api/orders/{id}")]
public async Task<IActionResult> Get(int id)
{
var order = await _orderService.GetByIdAsync(id);
return order is null ? NotFound() : Ok(order);
}
}
این طراحی چند مشکل جدی دارد:
• کنترلر مستقیماً به
OrderService Couple شده است.• تست Unit برای کنترلر سخت است، چون نمیتوان Mock تزریق کرد.
• در آینده اگر سرویس عوض شود (مثلاً کش اضافه شود)، باید خود کنترلر را تغییر بدهید.
راه تمیزتر این است که یک Interface تعریف کنید و آن را از DI Container تزریق کنید:
public interface IOrderService
{
Task<Order?> GetByIdAsync(int id);
}
public class OrderService : IOrderService
{
private readonly AppDbContext _db;
public OrderService(AppDbContext db)
{
_db = db;
}
public Task<Order?> GetByIdAsync(int id)
=> _db.Orders.FindAsync(id).AsTask();
}
حالا کنترلر فقط Interface را میشناسد:
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
private readonly IOrderService _orderService;
public OrdersController(IOrderService orderService)
{
_orderService = orderService;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id)
{
var order = await _orderService.GetByIdAsync(id);
return order is null ? NotFound() : Ok(order);
}
}
و در
Program.cs (یا Startup قدیمیها):builder.Services.AddScoped<IOrderService, OrderService>();
مزیتها 🧩
• تستپذیری بالا: در تستها میتوان یک
FakeOrderService یا Mock تزریق کرد.• پیادهسازی قابلتعویض: بدون تغییر کنترلر میتوانید
CachingOrderService اضافه کنید.• رعایت اصل D از SOLID (Dependency Inversion): وابستگی به Abstraction نه Concrete Class.
برای مطالعه بیشتر، مستندات رسمی مایکروسافت درباره DI در ASP.NET Core خیلی شفاف و بهروز است:
Microsoft Learn - Dependency injection in ASP.NET Core
قدمبهقدم اگر وابستگیهای مستقیم را به شکل Interface + DI تبدیل کنید، معماری اپلیکیشن تمیزتر، منعطفتر و آمادهٔ رشد میشود. 🚀
🔖 #CSharp #سی_شارپ #C# #_NET #ASP_NET_Core #Dependency_Injection #SOLID #Clean_Code
👤 Developix
💎 Channel: @DevelopixCSharp
👍3❤1