| کانال توسعه‌دهندگان سی‌شارپ |
1.03K subscribers
19 photos
3 videos
21 links
⭕️ کانال توسعه‌دهندگان سی‌شارپ دولوپیکس

💠 دولوپیکس | جامعه توسعه‌دهندگان ایرانی

💎 @Developix
🚀 Developix.ir

📌 پشتیبانی و تبلیغات:
@DevelopixSupport
Download Telegram
- معرفی BCL

BCL: Base Class Library

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

پکیج هایی که از nuget نصب میکنید، همگی بخشی از این کتابخانه ها هستن، مثلا newtonSoft ، automapper ، dapper و...

اما خود دات‌نت به طور مستقل یک کتابخانه مشترک و عمومی در اختیار توسعه دهنده قرار میده که اصطلاحا بهش BCL یا CL میگن؛ BCL بخشی از FCL هست که به طور مشترک در بین تمامی نسخه های دات‌نت وجود داره،
مواردی مثل data type ها مثل string, int, bool و List, Dictionary و تمام موارد این چنینی بخشی از BCL هستن،

درواقع BCL ، اولین خطی هست که توی برنامتون مینویسید(معمولا):
using System;

تمام type ها ، utility ها و بیشتر چیزهایی که از این namespace میاد، بخشی از BCL هست، مثلا:

System.Collections
System.Linq
System.Net
یا کلاس های HttpClient یا Stream

و خیلی مواردی که تا الان بهشون برخوردید همگی بخشی از این کتابخانه مشترک هستن، یکی از موارد مهمی که باید بهش توجه کنید، FCL و تفاوت این دو هست.

- معرفی FCL

FCL : Framework Class Library

مورد قبلی که بهش اشاره کردیم، Base بود ولی الان که کلمه framework رو دیدید احتمالا حدس میزنید که چه فرقی دارن، کاملا اشتباه حدس زدید، FCL مخصوص نسخه های .net framework نیست ، در واقع هیچ ربطی به اسمش نداره (باز هم نامگذاری های مایکروسافت).

‏FCL به تمام کد ها و کتابخانه های ارائه شده توسط دات‌نت گفته میشه، هر کدی که توسط مایکروسافت نوشته شده، توی این دسته قرار میگیره، مثلا asp.net ، wpf, winform و همچنین خود BCL همگی بخشی از FCL هستن؛

پس FCL یک مجموعه کلی از کتابخانه ها و ابزار های مایکروسافت هست که BCL فقط بخشی از اون هست.

اما چه فرقی میکنن ؟ چرا همشون یکجا توی BCL نیستن ؟
همونطور که بالاتر گفتم، BCL توی تمامی نسخه های دات‌نت وجود داره، فرقی نمیکنه سیستم عامل هدف چیه، cpu چی هست یا کدتون اصلا روی یخچال خونه میخواد اجرا بشه یا جای دیگه، هرجا که دات‌نت هست، تمامی کتابخانه های BCL وجود دارن؛
اما FCL محدود به محیط هست، شما طبیعتا روی یک یخچال نمیتونید WPF یا Winform اجرا کنید، اگر دات‌نت ورژن بخصوصی برای یخچال داشته باشه، قطعا شامل System.Windows نمیشه.
خب پس تمام مواردی که بین نسخه های مختلف دات‌نت مشترک هستند، بخشی از BCL هستند؛ و تمام مواردی که مشترک نیستند بخشی از FCL.

#CLR

👤 QWxp

💎 Channel: @DevelopixCSharp
👍9🔥1
اولین نسخه RC برای دات‌نت 8 منتشر شد.

تیم دات‌نت هم بجز System.Text.Json هیچ دغدغه دیگه ای نداره خداروشکر و به طور وحشیانه ای فیچر اضافه میکنن بهش

لینک معرفی

دانلود

مقایسه پرفورمنس (خیلی خلاصه نوشته)

👤 QWxp

💎 Channel: @DevelopixCSharp
👍6
معرفی کتابخانه RazorSlices

این کتابخانه یک template سبک و سریع برای asp.net core minimal api ساخته شده، بدون نیاز به استفاده از MVC، بهینه شده برای رندر کردن HTML در Razor یا Blazor.

برای شروع:
1.کتابخانه را نصب کنید
$ dotnet add package RazorSlices

2.یک دایرکتوری به نام Slices توی پروژتون ایجاد کنید، و داخل اون یک فایل به نام ViewImports.cshtml_ با این محتوا ایجاد کنید:
@inherits RazorSliceHttpResult
@using System.Globalization;
@using Microsoft.AspNetCore.Razor;
@using Microsoft.AspNetCore.Http.HttpResults;
@tagHelperPrefix disable_tagHelpers:
@removeTagHelper *, Microsoft.AspNetCore.Mvc.Razor
3. یک cshtml.* دیگه داخل دایرکتوری Slices ایجاد کنید :

@inherits RazorSliceHttpResult<DateTime>
<p>
Hello from Razor Slices! The time is @Model
</p>

4.حالا به راحتی داخل minimal api اتون صفحات HTML رو رندر کنید:

app.MapGet("/hello", () => Results.Extensions.RazorSlice("/Slices/Hello.cshtml", DateTime.Now));

🧷درحال حاضر موارد زیر در این کتابخانه پشتیبانی نمیشند:
1.پشتیبانی از AOT
2.پشتیبانی از Hot Reload
3.پشتیبانی از Layout ها و Section ها

#asp #razor

👤 QWxp

💎 Channel: @DevelopixCSharp
👍9
در پروژه‌های ASP.NET Core وقتی یک سرویس تعداد زیادی وابستگی دارد، خوانایی، تست‌پذیری و نگهداری کد سخت می‌شود.

ایده‌ی عملی امروز: به‌جای تزریق مستقیم چندین سرویس در یک کلاس، یک Facade یا Aggregate Service بسازید تا زنجیره‌ی وابستگی ساده، قابل تست و خواناتر شود. این رویکرد از Service Locator و constructor bloat جلوگیری می‌کند و مسئولیت‌ها را بهتر جدا می‌کند. 🧩

مثال واقعی: کلاس OrderService که به Inventory، Payment و Notification وابسته است. اول نسخهٔ «بد» با constructor پر از وابستگی‌ها:

<!-- escaped C# code for Telegram -->
public class OrderService
{
private readonly IInventoryService _inventory;
private readonly IPaymentService _payment;
private readonly INotificationService _notification;

public OrderService(IInventoryService inventory, IPaymentService payment, INotificationService notification)
{
_inventory = inventory;
_payment = payment;
_notification = notification;
}

public async Task<bool> PlaceOrderAsync(Order order)
{
if (!await _inventory.ReserveAsync(order)) return false;
var paid = await _payment.ChargeAsync(order);
if (!paid) { await _inventory.ReleaseAsync(order); return false; }
await _notification.SendAsync(order);
return true;
}
}


با الگوی Facade، مجموعهٔ عملیات مرتبط را در یک رابط قرار می‌دهیم تا OrderService ساده شود:

<!-- escaped C# code -->
public interface IOrderProcessor { Task<bool> ProcessAsync(Order order); }

public class OrderProcessor : IOrderProcessor
{
private readonly IInventoryService _inventory;
private readonly IPaymentService _payment;
private readonly INotificationService _notification;

public OrderProcessor(IInventoryService inventory, IPaymentService payment, INotificationService notification) { ... }

public async Task<bool> ProcessAsync(Order order)
{
// همان منطق ترکیبی اینجا قرار می‌گیرد
}
}

public class OrderService
{
private readonly IOrderProcessor _processor;
public OrderService(IOrderProcessor processor) { _processor = processor; }
public Task<bool> PlaceOrderAsync(Order order) => _processor.ProcessAsync(order);
}


نکات عملی:
• با Facade، تست واحد ساده‌تر می‌شود (فقط IOrderProcessor موک می‌شود). 🧪
• مسئولیت‌ها تمیز جدا می‌شوند و هر سرویس کوچک‌تر و تک‌وظیفه‌ای می‌ماند. ✂️
• از تزریق مستقیم تعداد زیادی سرویس در کنترلرها یا سرویس‌های سطح بالا خودداری کنید.

مراجع معتبر: مستندات Microsoft Dependency Injection و الگوهای طراحی در Refactoring.Guru برای جزئیات بیشتر. 📚

شروع به کوچک‌سازی زنجیره‌های تزریق در پروژه کنونی کنید و تغییرات را با تست‌های واحد همراه کنید — تاثیرش را سریع احساس خواهید کرد. 🚀

🔖 #CSharp #سی_شارپ #Facade #DependencyInjection #SOLID #C# #ASP_NET_Core

👤 Developix

💎 Channel: @DevelopixCSharp
2👍1
‏Dependency Injection تمیز در ASP.NET Core برای تست‌پذیری بهتر ⚙️

یکی از مهم‌ترین قدم‌ها برای 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
👍31
استفاده حرفه‌ای از ConfigureAwait(false) در async/await

خیلی وقت‌ها توی کتابخونه‌ها و لایه‌های غیر UI، از async/await استفاده می‌شه ولی ناخواسته Performance و Scale خراب می‌شه؛ فقط به خاطر برنگشتنِ درست به Thread قدیمی.

نکتهٔ مهم اینه: در کدهای غیر UI (مثل لایهٔ Data Access، Service، Library) معمولاً نیازی نیست بعد از await برگردیم به همون SynchronizationContext قبلی. اینجاست که 🧠 ConfigureAwait(false) کمک می‌کنه.

ایده:
هرجا در Library Code هستیم و بعد از await به Context قبلی نیاز نداریم، از ConfigureAwait(false) استفاده کنیم تا:
- Deadlockهای کلاسیک در ASP.NET قدیمی کمتر بشه
- Performance بهتر بشه چون نیاز به Capture/Restore Context نیست

مثال ساده در یک Service غیر UI:
public async Task<UserDto> GetUserAsync(int id)
{
// فرض: این متد توی لایه Service یا Repository صدا زده می‌شه
using var client = new HttpClient();

var response = await client
.GetAsync($"https://api.example.com/users/{id}")
.ConfigureAwait(false);

response.EnsureSuccessStatusCode();

var json = await response.Content
.ReadAsStringAsync()
.ConfigureAwait(false);

return JsonSerializer.Deserialize<UserDto>(json)!;
}


📌 نکات مهم:
- توی UI (WPF, WinForms, MAUI) یا Razor Pages که بعد از await می‌خوای کنترل‌های UI رو آپدیت کنی، از ConfigureAwait(false) استفاده نکن چون به Thread UI برنمی‌گردی.
- در ASP.NET Core به‌خاطر نداشتن SynchronizationContext کلاسیک، مشکل Deadlock خیلی کمتره؛ ولی هنوز هم برای Libraryهای عمومی، استفاده از ConfigureAwait(false) یک Practice خوب حساب می‌شه.
- سعی کن این الگو رو توی کل لایه‌های Library یک‌دست نگه داری تا رفتار کد قابل‌پیش‌بینی بمونه.

برای توضیح رسمی مایکروسافت دربارهٔ async/await و Context:
مستندات async در C# (Microsoft Docs)

امتحان این روش توی Serviceها و Libraryها، مخصوصاً زیر لود بالا، خیلی زود توی لاگ‌ها و Performance خودش رو نشون می‌ده 🚀

🔖 #CSharp #سی_شارپ #CSharp #async #ConfigureAwait #Performance #_NET

👤 Developix

💎 Channel: @DevelopixCSharp
🔥3
خیلی از Memory Leakهای ریز تو پروژه‌های #CSharp از یه چیز ساده شروع می‌شن: فراموش‌کردن Dispose روی resourceهایی مثل HttpClient، SqlConnection، فایل‌ها و… 😅

تو دات‌نت جدید، using راحت‌تر و خواناتر شده و اگر درست استفاده بشه، هم کد تمیزتر می‌شه هم از نشت حافظه و handleها جلوگیری می‌کنه. 👇

۱️⃣ الگوی قدیمی using بلاکی
using (var stream = File.OpenRead("data.json"))
using (var reader = new StreamReader(stream))
{
var content = reader.ReadToEnd();
Console.WriteLine(content);
}

اینجا به‌محض خروج از بلاک، هر دو object به‌صورت خودکار Dispose می‌شن.

۲️⃣ الگوی جدید using declaration (از C# 8 به بعد)
برای کاهش nesting و خوانایی بیشتر:
using var stream = File.OpenRead("data.json");
using var reader = new StreamReader(stream);

var content = reader.ReadToEnd();
Console.WriteLine(content);
// در انتهای متد، خودشون Dispose می‌شن

تو این حالت، scopeِ using var کل متده؛ یعنی پایان متد = زمان Dispose. این الگو توی متدهای کوتاه و تمیز عالی جواب می‌ده و از بلاک‌های تو در تو کم می‌کنه. 💡

۳️⃣ نکته مهم در متدهای طولانی
اگر متد خیلی طولانیه و resource فقط تو یه بخش کوچیک لازم می‌شه، بهتره همون الگوی بلاکی رو نگه داری تا resource زودتر آزاد بشه و تا آخر متد تو حافظه نمونه.

۴️⃣ async و IAsyncDisposable
برای کلاس‌هایی که IAsyncDisposable رو پیاده‌سازی می‌کنن (مثلاً بعضی clientهای شبکه):
await using var client = new SomeAsyncClient();
await client.DoWorkAsync();

اینجا در انتهای scope، به‌جای Dispose، متد DisposeAsync صدا زده می‌شه و resourceها به‌شکل async آزاد می‌شن.

جمع‌بندی: استفاده درست از using (به‌خصوص using var و await using) یه راه خیلی ساده و کاربردی برای جلوگیری از Memory Leak و تمیز نگه‌داشتن کده. چند جای پروژه رو که resource سنگین دارن چک و این الگو رو اعمال کن؛ تأثیرش تو performance و پایداری سرویس کاملاً قابل لمسه. 🚀

🔗 مرجع رسمی Microsoft Docs:
https://learn.microsoft.com/dotnet/csharp/language-reference/statements/using

🔖 #CSharp #سی_شارپ #C# #using #dispose #memory #performance #_NET

👤 Developix

💎 Channel: @DevelopixCSharp
1
🕒 NodaTime؛ خداحافظ DateTime گیج‌کننده

کار با DateTime و TimeZone در .NET مخصوصاً در پروژه‌های چندمنطقه‌ای واقعاً دردسرسازه؛ از UTC و Local گرفته تا DST و Offsetهای مختلف.

اینجا NodaTime وارد می‌شه؛ یک کتابخانه قدرتمند برای مدیریت زمان و تاریخ که مدلش خیلی شفاف‌تر از DateTime پیش‌فرضه و توی پروژه‌های مالی، رزرو، لاگینگ و سرویس‌های بین‌المللی عالی جواب می‌ده. 🚀

چرا NodaTime؟
• تایپ‌های واضح مثل Instant، LocalDate، LocalDateTime، ZonedDateTime
• پشتیبانی دقیق از IANA Time Zone
• جلوگیری از باگ‌های زمان‌بندی، مخصوصاً اطراف تغییر ساعت (DST)
• API تمیز و قابل تست؛ مخصوصاً برای Domain-Driven Design

نصب با NuGet:
dotnet add package NodaTime


نمونه استفاده ساده:
using NodaTime;

var now = SystemClock.Instance.GetCurrentInstant();
var tz = DateTimeZoneProviders.Tzdb["Europe/Berlin"];
var zoned = now.InZone(tz);

LocalDate invoiceDate = new(2026, 1, 26);
LocalDate dueDate = invoiceDate.PlusDays(14);


برای هر سرویسی که زمان و زمان‌بندی توش مهمه، همراه کردنش با NodaTime جلوی کلی Memory Bug و رفتار عجیب رو می‌گیره. پیشنهاد می‌شه حتماً تو پروژه بعدی امتحان بشه و کم‌کم DateTime خام رو کنار بذاری. 💡

مستندات رسمی:
Website & Docs
GitHub

🔖 #CSharp #سی_شارپ #CSharp #NodaTime #_NET #Time #DateTime #Backend

👤 Developix

💎 Channel: @DevelopixCSharp
👍4