پاسخ:
.NET Core (که اکنون به سادگی .NET نامیده میشود) و .NET Framework هر دو پلتفرمهای توسعه نرمافزار از مایکروسافت هستند که برای ساخت انواع مختلفی از برنامهها استفاده میشوند.
پاسخ:
Common Language Runtime (CLR) جزء اصلی پلتفرم .NET است که مسئول مدیریت و اجرای کد .NET است.
پاسخ:
دستور dotnet new بخشی از .NET CLI است و برای ایجاد پروژههای جدید، فایلها یا راهحلها بر اساس الگوهای از پیش تعریف شده استفاده میشود.
dotnet new console -o MyConsoleApp dotnet new webapi -o MyWebApi dotnet new sln -n MySolution dotnet new list
پاسخ:
.NET Core از ابتدا با هدف پشتیبانی از توسعه کراسپلتفرم طراحی شده است.
System.Collections, System.IO روی تمام پلتفرمها کار میکنندپاسخ:
Kestrel یک وب سرور کراسپلتفرم، سبک و بسیار سریع است که به طور پیشفرض در پروژههای ASP.NET Core استفاده میشود.
پاسخ:
Middleware کامپوننتهای نرمافزاری هستند که در خط لوله پردازش درخواست قرار میگیرند و میتوانند درخواستهای HTTP و پاسخها را بررسی، مسیریابی یا اصلاح کنند.
var builder = WebApplication.CreateBuilder(args); var app = builder.Build(); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
پاسخ:
هر دو دستور بخشی از .NET CLI هستند اما هدف متفاوتی دارند:
bin قرار میگیردdotnet build را اجرا میکندdotnet run در طول توسعه و از dotnet build در CI/CD استفاده میکنند.
پاسخ:
appsettings.json فایل پیکربندی در پروژههای ASP.NET Core است که برای ذخیره تنظیمات برنامه استفاده میشود.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=MyDB;Trusted_Connection=True;"
},
"ApiKey": "MySecretApiKey"
}
public class MyController : ControllerBase
{
private readonly IConfiguration _configuration;
public MyController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public IActionResult GetApiKey()
{
string apiKey = _configuration["ApiKey"];
string connectionString = _configuration.GetConnectionString("DefaultConnection");
return Ok(new { ApiKey = apiKey });
}
}
پاسخ:
هر دو به عنوان نوع بازگشتی برای متدهای اکشن در کنترلرهای ASP.NET Core استفاده میشوند:
OkObjectResult, NotFoundResult, JsonResultpublic IActionResult GetUser(int id)
{
if (id <= 0)
return BadRequest("Invalid ID");
var user = GetUserById(id);
if (user == null)
return NotFound();
return Ok(user);
}
public ActionResult<User> GetUser(int id)
{
if (id <= 0)
return BadRequest("Invalid ID");
var user = GetUserById(id);
if (user == null)
return NotFound();
return user; // بازگشت مستقیم نوع User
}
ActionResult<T> استفاده کنید.
پاسخ:
Service Lifetime تعیین میکند که چگونه و چه زمانی نمونههای سرویسها در Dependency Injection ایجاد و مدیریت میشوند.
// در Program.cs builder.Services.AddSingleton<ISingletonService, SingletonService>(); builder.Services.AddScoped<IScopedService, ScopedService>(); builder.Services.AddTransient<ITransientService, TransientService>();
پاسخ:
Repository Pattern یک الگوی طراحی است که لایهای از انتزاع بین منطق کسبوکار و لایه دسترسی به داده ایجاد میکند.
public interface IUserRepository
{
Task<User> GetByIdAsync(int id);
Task<IEnumerable<User>> GetAllAsync();
Task AddAsync(User user);
Task UpdateAsync(User user);
Task DeleteAsync(int id);
}
public class UserRepository : IUserRepository
{
private readonly ApplicationDbContext _context;
public UserRepository(ApplicationDbContext context)
{
_context = context;
}
public async Task<User> GetByIdAsync(int id)
{
return await _context.Users.FindAsync(id);
}
}
پاسخ:
Entity Framework Core یک ORM (Object-Relational Mapping) مدرن و سبک برای .NET است که دسترسی به پایگاه داده را سادهتر میکند.
// تعریف DbContext
public class ApplicationDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(connectionString);
}
}
// استفاده از LINQ
var activeUsers = await _context.Users
.Where(u => u.IsActive)
.OrderBy(u => u.Name)
.ToListAsync();
پاسخ:
LINQ (Language Integrated Query) یک فناوری در .NET است که امکان نوشتن کوئریهای یکپارچه روی انواع مختلف منابع داده را فراهم میکند.
// Query Syntax
var result = from user in users
where user.Age > 18
orderby user.Name
select new { user.Name, user.Email };
// Method Syntax
var result = users
.Where(u => u.Age > 18)
.OrderBy(u => u.Name)
.Select(u => new { u.Name, u.Email });
// عملیاتهای رایج
var count = users.Count(u => u.IsActive);
var firstUser = users.FirstOrDefault(u => u.Id == 1);
var groupedUsers = users.GroupBy(u => u.Department);
پاسخ:
Lambda Expression راهی مختصر برای نوشتن توابع ناشناس (Anonymous Functions) در C# است که بیشتر با LINQ و Delegates استفاده میشود.
// ساختار کلی: (parameters) => expression یا statement
// Lambda ساده
x => x * 2
// Lambda با چند پارامتر
(x, y) => x + y
// Lambda با بدنه
x => {
Console.WriteLine($"Processing: {x}");
return x * 2;
}
// با LINQ
var evenNumbers = numbers.Where(n => n % 2 == 0);
var doubled = numbers.Select(n => n * 2);
// با Delegates
Action<string> print = message => Console.WriteLine(message);
Func<int, int, int> add = (a, b) => a + b;
// Event Handling
button.Click += (sender, e) => MessageBox.Show("Clicked!");
// Async Lambda
var result = await Task.Run(() => SomeHeavyOperation());
پاسخ:
async/await الگویی در C# برای نوشتن کد ناهمزمان (Asynchronous) است که به شکل همزمان نوشته میشود.
// متد async
public async Task<string> GetDataAsync()
{
using var httpClient = new HttpClient();
var response = await httpClient.GetStringAsync("https://api.example.com/data");
return response;
}
// استفاده از async/await
public async Task ProcessDataAsync()
{
try
{
var data = await GetDataAsync();
Console.WriteLine($"Received: {data}");
}
catch (HttpRequestException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
}
[HttpGet]
public async Task<ActionResult<List<User>>> GetUsersAsync()
{
var users = await _userService.GetAllUsersAsync();
return Ok(users);
}
پاسخ:
Task و Thread هر دو برای اجرای کد به صورت موازی استفاده میشوند، اما تفاوتهای مهمی دارند:
// استفاده از Thread
var thread = new Thread(() => {
Console.WriteLine("Running on thread");
});
thread.Start();
thread.Join();
// استفاده از Task
var task = Task.Run(() => {
Console.WriteLine("Running on task");
});
await task;
// Task با نتیجه
var result = await Task.Run(() => {
return SomeCalculation();
});
پاسخ:
Garbage Collection (GC) مکانیزم خودکار مدیریت حافظه در .NET است که حافظه اشغال شده توسط اشیاء غیرقابل دسترس را آزاد میکند.
// کنترل دستی GC (توصیه نمیشود)
GC.Collect();
GC.WaitForPendingFinalizers();
// بررسی وضعیت حافظه
var gen0 = GC.CollectionCount(0);
var totalMemory = GC.GetTotalMemory(false);
// استفاده از using برای مدیریت منابع
using (var fileStream = new FileStream("file.txt", FileMode.Open))
{
// کار با فایل
} // خودکار Dispose میشود
پاسخ:
IDisposable اینترفیسی است که برای آزادسازی منابع غیرمدیریت شده (Unmanaged Resources) مانند فایلها، اتصالات پایگاه داده، و Socket ها استفاده میشود.
public class DatabaseConnection : IDisposable
{
private SqlConnection _connection;
private bool _disposed = false;
public DatabaseConnection(string connectionString)
{
_connection = new SqlConnection(connectionString);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
// آزادسازی منابع مدیریت شده
_connection?.Dispose();
}
// آزادسازی منابع غیرمدیریت شده
_disposed = true;
}
}
~DatabaseConnection()
{
Dispose(false);
}
}
// using statement
using (var connection = new DatabaseConnection(connectionString))
{
// کار با اتصال
} // خودکار Dispose میشود
// using declaration (C# 8+)
using var connection = new DatabaseConnection(connectionString);
// کار با اتصال
// در پایان scope خودکار Dispose میشود
پاسخ:
سیستم Configuration در ASP.NET Core امکان خواندن تنظیمات از منابع مختلف را با اولویتبندی فراهم میکند.
// در Program.cs
var builder = WebApplication.CreateBuilder(args);
// اضافه کردن منابع Configuration
builder.Configuration
.AddJsonFile("appsettings.json", optional: false)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables()
.AddCommandLine(args);
var app = builder.Build();
// دسترسی مستقیم
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
var apiKey = builder.Configuration["ApiSettings:Key"];
// Options Pattern
public class ApiSettings
{
public string Key { get; set; }
public string BaseUrl { get; set; }
}
builder.Services.Configure<ApiSettings>(
builder.Configuration.GetSection("ApiSettings"));
// در کنترلر
public class HomeController : Controller
{
private readonly ApiSettings _apiSettings;
public HomeController(IOptions<ApiSettings> apiSettings)
{
_apiSettings = apiSettings.Value;
}
}
پاسخ:
Logging در ASP.NET Core یک سیستم انعطافپذیر و قدرتمند برای ثبت رویدادها و خطاهای برنامه است.
// پیکربندی در appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.EntityFrameworkCore": "Information"
}
}
}
public class HomeController : Controller
{
private readonly ILogger<HomeController> _logger;
public HomeController(ILogger<HomeController> logger)
{
_logger = logger;
}
public IActionResult Index()
{
_logger.LogInformation("Home page visited at {Time}", DateTime.Now);
try
{
// کد اصلی
return View();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred in Home/Index");
return View("Error");
}
}
}
// در Program.cs builder.Logging.ClearProviders(); builder.Logging.AddConsole(); builder.Logging.AddDebug(); builder.Logging.AddEventSourceLogger(); // Third-party providers builder.Logging.AddSerilog(); builder.Logging.AddNLog();
پاسخ:
این دو مفهوم امنیتی اغلب با هم اشتباه گرفته میشوند، اما نقشهای متفاوتی دارند:
// در ASP.NET Core
// Authentication
app.UseAuthentication(); // بررسی توکن یا کوکی
// Authorization
app.UseAuthorization(); // بررسی نقشها و سیاستها
[Authorize] // نیاز به احراز هویت
public class SecureController : ControllerBase { }
[Authorize(Roles = "Admin")] // نیاز به نقش ادمین
public class AdminController : ControllerBase { }
[Authorize(Policy = "CanEditProducts")] // نیاز به سیاست خاص
public class ProductController : ControllerBase { }
پاسخ:
JWT (JSON Web Token) یک استاندارد باز برای ایجاد توکنهای دسترسی است که اطلاعات را به صورت JSON بین دو طرف منتقل میکند.
// پیکربندی JWT در Program.cs
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
// ایجاد توکن
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()),
new Claim(ClaimTypes.Role, "Admin")
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds
);
var tokenString = new JwtSecurityTokenHandler().WriteToken(token);
پاسخ:
CORS (Cross-Origin Resource Sharing) مکانیزمی است که به یک برنامه وب اجازه میدهد تا از منابع یک دامنه دیگر درخواست کند.
// در Program.cs
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://www.example.com",
"https://app.example.com")
.WithMethods("GET", "POST", "PUT")
.WithHeaders("Content-Type", "Authorization");
});
});
var app = builder.Build();
app.UseCors(MyAllowSpecificOrigins);
app.Run();
[EnableCors("_myAllowSpecificOrigins")]
[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase { }
[DisableCors]
public class AnotherController : ControllerBase { }
AllowAnyOrigin() در تولید خودداری کنید.
پاسخ:
Health Checks یک ویژگی در ASP.NET Core است که یک endpoint برای گزارش وضعیت سلامت برنامه فراهم میکند.
// در Program.cs
builder.Services.AddHealthChecks()
.AddDbContextCheck<ApplicationDbContext>("Database")
.AddUrlGroup(new Uri("https://api.example.com/status"), "External API");
var app = builder.Build();
app.MapHealthChecks("/health");
app.Run();
/health، وضعیت سلامت برنامه و وابستگیهای آن (مانند پایگاه داده) نمایش داده میشود.
پاسخ:
Minimal APIs یک رویکرد جدید در .NET 6+ برای ساخت APIهای سبک و سریع با کد کمتر است.
Program.cs// Minimal API در Program.cs
var app = WebApplication.Create();
app.MapGet("/", () => "Hello World!");
app.MapGet("/users/{id}", (int id, IUserService userService) =>
{
var user = userService.GetById(id);
return user is not null ? Results.Ok(user) : Results.NotFound();
});
app.Run();
پاسخ:
هر دو برای کار با کالکشنها استفاده میشوند، اما نحوه اجرای کوئریها متفاوت است:
// تمام کاربران به حافظه منتقل میشوند IEnumerable<User> users = _context.Users.ToList(); // فیلتر در حافظه انجام میشود var activeUsers = users.Where(u => u.IsActive);
// کوئری ساخته میشود اما اجرا نمیشود IQueryable<User> users = _context.Users; // فیلتر به کوئری SQL اضافه میشود var activeUsersQuery = users.Where(u => u.IsActive); // کوئری در پایگاه داده اجرا میشود var result = activeUsersQuery.ToList();
پاسخ:
این دو مفهوم به تبدیل بین Value Types (مانند int, struct) و Reference Types (مانند object) اشاره دارند.
int i = 123; object o = i; // Boxing
InvalidCastException رخ میدهدobject o = 123; int i = (int)o; // Unboxing
پاسخ:
این دو ساختار اصلی برای تعریف انواع داده در C# هستند:
public struct Point
{
public int X { get; set; }
public int Y { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}
int).
پاسخ:
SOLID مجموعهای از پنج اصل طراحی شیءگرا است که به توسعهدهندگان کمک میکند تا نرمافزاری قابل فهم، انعطافپذیر و قابل نگهداری بسازند.
پاسخ:
Unit Test نوعی تست نرمافزار است که کوچکترین بخشهای قابل تست یک برنامه (واحدها یا Unit ها) را به صورت جداگانه و مستقل آزمایش میکند.
// فریمورکهای تست در .NET
// xUnit, NUnit, MSTest
// مثال با xUnit و Moq
public class CalculatorTests
{
[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
// Arrange
var calculator = new Calculator();
// Act
var result = calculator.Add(2, 3);
// Assert
Assert.Equal(5, result);
}
}
// Mock کردن وابستگیها
[Fact]
public void GetUser_WithValidId_ReturnsUser()
{
// Arrange
var mockRepo = new Mock<IUserRepository>();
mockRepo.Setup(repo => repo.GetById(1)).Returns(new User { Id = 1, Name = "Test" });
var service = new UserService(mockRepo.Object);
// Act
var result = service.GetUser(1);
// Assert
Assert.NotNull(result);
Assert.Equal(1, result.Id);
}
پاسخ:
Migration در Entity Framework Core روشی برای مدیریت تغییرات ساختار پایگاه داده به صورت کنترل شده و قابل ردیابی است.
// ایجاد Migration جدید dotnet ef migrations add InitialCreate // اعمال Migration به پایگاه داده dotnet ef database update // حذف آخرین Migration dotnet ef migrations remove // مشاهده لیست Migration ها dotnet ef migrations list
public partial class AddUserTable : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(100)", maxLength: 100, nullable: false),
Email = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
});
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(name: "Users");
}
}
پاسخ:
دو رویکرد مختلف برای کار با Entity Framework Core:
// تعریف مدل
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<Order> Orders { get; set; }
}
// DbContext
public class ApplicationDbContext : DbContext
{
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(u => u.Name)
.HasMaxLength(100)
.IsRequired();
}
}
Scaffold-DbContext// تولید مدل از پایگاه داده dotnet ef dbcontext scaffold "Server=.;Database=MyDB;Trusted_Connection=true;" Microsoft.EntityFrameworkCore.SqlServer -o Models
پاسخ:
Lazy Loading یک الگو در Entity Framework است که دادههای مرتبط را تنها زمانی بارگذاری میکند که به آنها دسترسی پیدا شود.
// نصب پکیج
// Microsoft.EntityFrameworkCore.Proxies
// فعالسازی در DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseLazyLoadingProxies()
.UseSqlServer(connectionString);
}
// تعریف Navigation Properties به صورت virtual
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public virtual List<Order> Orders { get; set; } // virtual برای Lazy Loading
}
// Lazy Loading - دادهها در زمان دسترسی بارگذاری میشوند
var user = context.Users.First();
var orders = user.Orders; // در اینجا کوئری اجرا میشود
// Eager Loading - دادهها از ابتدا بارگذاری میشوند
var userWithOrders = context.Users
.Include(u => u.Orders)
.First();
پاسخ:
بهینهسازی عملکرد در ASP.NET Core شامل تکنیکهای مختلفی است:
// Response Caching
[ResponseCache(Duration = 300)] // 5 دقیقه
public IActionResult GetProducts()
{
return Ok(products);
}
// Memory Caching
public class ProductService
{
private readonly IMemoryCache _cache;
public async Task<List<Product>> GetProductsAsync()
{
if (!_cache.TryGetValue("products", out List<Product> products))
{
products = await _repository.GetAllAsync();
_cache.Set("products", products, TimeSpan.FromMinutes(10));
}
return products;
}
}
// Response Compression در Program.cs
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>();
});
app.UseResponseCompression();
پاسخ:
Caching یکی از مهمترین تکنیکهای بهبود عملکرد است که در ASP.NET Core به روشهای مختلف قابل پیادهسازی است:
// In-Memory Caching
builder.Services.AddMemoryCache();
public class HomeController : Controller
{
private readonly IMemoryCache _memoryCache;
public HomeController(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
}
public async Task<IActionResult> Index()
{
var cacheKey = "product-list";
if (!_memoryCache.TryGetValue(cacheKey, out List<Product> products))
{
products = await _productService.GetAllAsync();
var cacheOptions = new MemoryCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),
SlidingExpiration = TimeSpan.FromMinutes(2)
};
_memoryCache.Set(cacheKey, products, cacheOptions);
}
return View(products);
}
}
// در Program.cs
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
});
// استفاده
public class ProductService
{
private readonly IDistributedCache _distributedCache;
public async Task<List<Product>> GetProductsAsync()
{
var cacheKey = "products";
var cachedProducts = await _distributedCache.GetStringAsync(cacheKey);
if (cachedProducts != null)
{
return JsonSerializer.Deserialize<List<Product>>(cachedProducts);
}
var products = await _repository.GetAllAsync();
var serializedProducts = JsonSerializer.Serialize(products);
await _distributedCache.SetStringAsync(cacheKey, serializedProducts, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
});
return products;
}
}
پاسخ:
SignalR یک کتابخانه برای ASP.NET Core است که امکان ارتباط دوطرفه و real-time بین سرور و کلاینت را فراهم میکند.
// تعریف Hub
public class ChatHub : Hub
{
public async Task SendMessage(string user, string message)
{
await Clients.All.SendAsync("ReceiveMessage", user, message);
}
public async Task JoinGroup(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
await Clients.Group(groupName).SendAsync("UserJoined", Context.User.Identity.Name);
}
}
// پیکربندی در Program.cs
builder.Services.AddSignalR();
app.MapHub<ChatHub>("/chathub");
const connection = new signalR.HubConnectionBuilder()
.withUrl("/chathub")
.build();
// دریافت پیام
connection.on("ReceiveMessage", function (user, message) {
const msg = user + ": " + message;
document.getElementById("messagesList").innerHTML += "<li>" + msg + "</li>";
});
// ارسال پیام
document.getElementById("sendButton").addEventListener("click", function (event) {
const user = document.getElementById("userInput").value;
const message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
console.error(err.toString());
});
event.preventDefault();
});
// شروع اتصال
connection.start();
پاسخ:
Background Services امکان اجرای کارهای پسزمینه در ASP.NET Core را فراهم میکنند، مانند پردازش صف، ارسال ایمیل، یا کارهای دورهای.
public class EmailBackgroundService : BackgroundService
{
private readonly ILogger<EmailBackgroundService> _logger;
private readonly IServiceProvider _serviceProvider;
public EmailBackgroundService(ILogger<EmailBackgroundService> logger, IServiceProvider serviceProvider)
{
_logger = logger;
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var emailService = scope.ServiceProvider.GetRequiredService<IEmailService>();
try
{
await emailService.ProcessPendingEmailsAsync();
_logger.LogInformation("Email processing completed at: {time}", DateTimeOffset.Now);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error occurred executing email service");
}
}
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
}
// در Program.cs builder.Services.AddHostedService<EmailBackgroundService>();
پاسخ:
API Versioning امکان نگهداری چندین نسخه از API به صورت همزمان را فراهم میکند تا سازگاری با کلاینتهای قدیمی حفظ شود.
/api/v1/users/api/users?version=1.0X-Version: 1.0Accept: application/vnd.myapi.v1+json// نصب پکیج
// Microsoft.AspNetCore.Mvc.Versioning
// پیکربندی در Program.cs
builder.Services.AddApiVersioning(opt =>
{
opt.DefaultApiVersion = new ApiVersion(1, 0);
opt.AssumeDefaultVersionWhenUnspecified = true;
opt.ApiVersionReader = ApiVersionReader.Combine(
new UrlSegmentApiVersionReader(),
new QueryStringApiVersionReader("version"),
new HeaderApiVersionReader("X-Version")
);
});
builder.Services.AddVersionedApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'VVV";
setup.SubstituteApiVersionInUrl = true;
});
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class UsersV1Controller : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<UserV1>> Get()
{
return Ok(usersV1);
}
}
[ApiController]
[ApiVersion("2.0")]
[Route("api/v{version:apiVersion}/[controller]")]
public class UsersV2Controller : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<UserV2>> Get()
{
return Ok(usersV2);
}
}
پاسخ:
Rate Limiting تکنیکی برای محدود کردن تعداد درخواستهایی است که یک کلاینت میتواند در بازه زمانی مشخص ارسال کند.
// در Program.cs
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("FixedPolicy", opt =>
{
opt.PermitLimit = 10;
opt.Window = TimeSpan.FromMinutes(1);
opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
opt.QueueLimit = 5;
});
options.AddSlidingWindowLimiter("SlidingPolicy", opt =>
{
opt.PermitLimit = 100;
opt.Window = TimeSpan.FromMinutes(1);
opt.SegmentsPerWindow = 6;
});
});
var app = builder.Build();
app.UseRateLimiter();
[EnableRateLimiting("FixedPolicy")]
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public ActionResult<IEnumerable<Product>> Get()
{
return Ok(products);
}
[EnableRateLimiting("SlidingPolicy")]
[HttpPost]
public ActionResult<Product> Post(Product product)
{
// ایجاد محصول
return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
}
}
پاسخ:
Docker پلتفرمی برای containerization است که امکان بستهبندی برنامههای .NET همراه با تمام وابستگیها را فراهم میکند.
# استفاده از runtime image FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base WORKDIR /app EXPOSE 80 EXPOSE 443 # استفاده از SDK image برای build FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build WORKDIR /src COPY ["MyApp/MyApp.csproj", "MyApp/"] RUN dotnet restore "MyApp/MyApp.csproj" COPY . . WORKDIR "/src/MyApp" RUN dotnet build "MyApp.csproj" -c Release -o /app/build FROM build AS publish RUN dotnet publish "MyApp.csproj" -c Release -o /app/publish FROM base AS final WORKDIR /app COPY --from=publish /app/publish . ENTRYPOINT ["dotnet", "MyApp.dll"]
# ساخت image docker build -t myapp . # اجرای container docker run -d -p 8080:80 --name myapp-container myapp # مشاهده لاگها docker logs myapp-container # ورود به container docker exec -it myapp-container /bin/bash
پاسخ:
Microservices یک الگوی معماری است که برنامه را به مجموعهای از سرویسهای کوچک، مستقل و قابل استقرار جداگانه تقسیم میکند.
پاسخ:
API Gateway یک سرویس واسط است که به عنوان نقطه ورودی واحد برای تمام درخواستهای کلاینت به میکروسرویسها عمل میکند.
// نصب پکیج
// Ocelot
// ocelot.json
{
"Routes": [
{
"DownstreamPathTemplate": "/api/users/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5001
}
],
"UpstreamPathTemplate": "/users/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
},
{
"DownstreamPathTemplate": "/api/products/{everything}",
"DownstreamScheme": "https",
"DownstreamHostAndPorts": [
{
"Host": "localhost",
"Port": 5002
}
],
"UpstreamPathTemplate": "/products/{everything}",
"UpstreamHttpMethod": [ "GET", "POST", "PUT", "DELETE" ]
}
]
}
// Program.cs
builder.Configuration.AddJsonFile("ocelot.json");
builder.Services.AddOcelot();
var app = builder.Build();
await app.UseOcelot();
پاسخ:
Message Queue و Service Bus الگوهایی برای ارتباط ناهمزمان بین سرویسها هستند که امکان decoupling و مقیاسپذیری را فراهم میکنند.
// تعریف پیام
public class OrderCreated
{
public int OrderId { get; set; }
public string CustomerEmail { get; set; }
public decimal Amount { get; set; }
}
// Publisher
public class OrderService
{
private readonly IPublishEndpoint _publishEndpoint;
public OrderService(IPublishEndpoint publishEndpoint)
{
_publishEndpoint = publishEndpoint;
}
public async Task CreateOrderAsync(Order order)
{
// ذخیره سفارش
await _repository.SaveAsync(order);
// ارسال پیام
await _publishEndpoint.Publish(new OrderCreated
{
OrderId = order.Id,
CustomerEmail = order.CustomerEmail,
Amount = order.Amount
});
}
}
// Consumer
public class EmailNotificationConsumer : IConsumer<OrderCreated>
{
private readonly IEmailService _emailService;
public EmailNotificationConsumer(IEmailService emailService)
{
_emailService = emailService;
}
public async Task Consume(ConsumeContext<OrderCreated> context)
{
await _emailService.SendOrderConfirmationAsync(
context.Message.CustomerEmail,
context.Message.OrderId
);
}
}
پاسخ:
Circuit Breaker الگویی برای مدیریت خرابیهای شبکه و سرویسهای خارجی است که از cascade failure جلوگیری میکند.
// نصب پکیج
// Polly
// پیکربندی Circuit Breaker
var circuitBreakerPolicy = Policy
.Handle<HttpRequestException>()
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: 3,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (exception, duration) =>
{
Console.WriteLine($"Circuit breaker opened for {duration}");
},
onReset: () =>
{
Console.WriteLine("Circuit breaker reset");
});
// استفاده
public class ExternalApiService
{
private readonly HttpClient _httpClient;
private readonly IAsyncPolicy _circuitBreakerPolicy;
public ExternalApiService(HttpClient httpClient, IAsyncPolicy circuitBreakerPolicy)
{
_httpClient = httpClient;
_circuitBreakerPolicy = circuitBreakerPolicy;
}
public async Task<string> GetDataAsync()
{
try
{
return await _circuitBreakerPolicy.ExecuteAsync(async () =>
{
var response = await _httpClient.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
});
}
catch (CircuitBreakerOpenException)
{
// بازگشت داده کش شده یا پیام خطا
return "Service temporarily unavailable";
}
}
}
پاسخ:
Retry Pattern الگویی برای مدیریت خطاهای موقت است که عملیات ناموفق را چندین بار تکرار میکند.
// پیادهسازی با Polly
var retryPolicy = Policy
.Handle<HttpRequestException>()
.Or<TaskCanceledException>()
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), // Exponential backoff
onRetry: (outcome, delay, retryCount, context) =>
{
Console.WriteLine($"Retry {retryCount} after {delay} seconds");
});
// ترکیب Retry و Circuit Breaker
var combinedPolicy = Policy.WrapAsync(retryPolicy, circuitBreakerPolicy);
public async Task<ApiResponse> CallExternalApiAsync()
{
return await combinedPolicy.ExecuteAsync(async () =>
{
var response = await _httpClient.GetAsync("https://api.example.com/data");
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync<ApiResponse>();
});
}
پاسخ:
Distributed Tracing تکنیکی برای ردیابی درخواستها در سیستمهای توزیع شده است که امکان مشاهده مسیر کامل یک درخواست در چندین سرویس را فراهم میکند.
// نصب پکیجها
// OpenTelemetry
// OpenTelemetry.Extensions.Hosting
// OpenTelemetry.Exporter.Jaeger
// پیکربندی در Program.cs
builder.Services.AddOpenTelemetry()
.WithTracing(builder =>
{
builder
.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddEntityFrameworkCoreInstrumentation()
.AddJaegerExporter();
});
// استفاده در کد
public class OrderService
{
private static readonly ActivitySource ActivitySource = new("OrderService");
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
using var activity = ActivitySource.StartActivity("CreateOrder");
activity?.SetTag("order.customerId", request.CustomerId);
// منطق ایجاد سفارش
var order = new Order { CustomerId = request.CustomerId };
// فراخوانی سرویس دیگر
using var paymentActivity = ActivitySource.StartActivity("ProcessPayment");
await _paymentService.ProcessPaymentAsync(order.Id, request.Amount);
return order;
}
}
پاسخ:
Event Sourcing الگویی است که به جای ذخیره وضعیت فعلی، تمام تغییرات (events) را ذخیره میکند و وضعیت فعلی را از روی این رویدادها بازسازی میکند.
// تعریف Events
public abstract class Event
{
public Guid Id { get; set; } = Guid.NewGuid();
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
}
public class AccountCreated : Event
{
public Guid AccountId { get; set; }
public string AccountHolder { get; set; }
public decimal InitialBalance { get; set; }
}
public class MoneyDeposited : Event
{
public Guid AccountId { get; set; }
public decimal Amount { get; set; }
}
public class MoneyWithdrawn : Event
{
public Guid AccountId { get; set; }
public decimal Amount { get; set; }
}
// Aggregate
public class Account
{
public Guid Id { get; private set; }
public string AccountHolder { get; private set; }
public decimal Balance { get; private set; }
private readonly List<Event> _events = new();
public void CreateAccount(string accountHolder, decimal initialBalance)
{
var @event = new AccountCreated
{
AccountId = Guid.NewGuid(),
AccountHolder = accountHolder,
InitialBalance = initialBalance
};
Apply(@event);
_events.Add(@event);
}
public void Deposit(decimal amount)
{
var @event = new MoneyDeposited { AccountId = Id, Amount = amount };
Apply(@event);
_events.Add(@event);
}
private void Apply(AccountCreated @event)
{
Id = @event.AccountId;
AccountHolder = @event.AccountHolder;
Balance = @event.InitialBalance;
}
private void Apply(MoneyDeposited @event)
{
Balance += @event.Amount;
}
public IEnumerable<Event> GetUncommittedEvents() => _events;
}
پاسخ:
CQRS (Command Query Responsibility Segregation) الگویی است که عملیات خواندن (Query) و نوشتن (Command) را از هم جدا میکند.
// Commands (نوشتن)
public class CreateUserCommand : IRequest<int>
{
public string Name { get; set; }
public string Email { get; set; }
}
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, int>
{
private readonly IUserRepository _repository;
public CreateUserCommandHandler(IUserRepository repository)
{
_repository = repository;
}
public async Task<int> Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
var user = new User { Name = request.Name, Email = request.Email };
await _repository.AddAsync(user);
return user.Id;
}
}
// Queries (خواندن)
public class GetUserQuery : IRequest<UserDto>
{
public int UserId { get; set; }
}
public class GetUserQueryHandler : IRequestHandler<GetUserQuery, UserDto>
{
private readonly IUserReadRepository _readRepository;
public GetUserQueryHandler(IUserReadRepository readRepository)
{
_readRepository = readRepository;
}
public async Task<UserDto> Handle(GetUserQuery request, CancellationToken cancellationToken)
{
return await _readRepository.GetUserDtoAsync(request.UserId);
}
}
// در کنترلر
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
private readonly IMediator _mediator;
public UsersController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<ActionResult> CreateUser(CreateUserCommand command)
{
var userId = await _mediator.Send(command);
return CreatedAtAction(nameof(GetUser), new { id = userId }, null);
}
[HttpGet("{id}")]
public async Task<ActionResult<UserDto>> GetUser(int id)
{
var user = await _mediator.Send(new GetUserQuery { UserId = id });
return Ok(user);
}
}
پاسخ:
Domain-Driven Design رویکردی برای توسعه نرمافزار است که بر روی مدلسازی دقیق domain کسبوکار تمرکز دارد.
// Value Object
public class Money
{
public decimal Amount { get; private set; }
public string Currency { get; private set; }
public Money(decimal amount, string currency)
{
if (amount < 0) throw new ArgumentException("Amount cannot be negative");
Amount = amount;
Currency = currency ?? throw new ArgumentNullException(nameof(currency));
}
public Money Add(Money other)
{
if (Currency != other.Currency)
throw new InvalidOperationException("Cannot add different currencies");
return new Money(Amount + other.Amount, Currency);
}
}
// Entity
public class Order
{
public int Id { get; private set; }
public DateTime OrderDate { get; private set; }
public Money TotalAmount { get; private set; }
private readonly List<OrderItem> _items = new();
public IReadOnlyList<OrderItem> Items => _items.AsReadOnly();
public void AddItem(Product product, int quantity)
{
var existingItem = _items.FirstOrDefault(i => i.ProductId == product.Id);
if (existingItem != null)
{
existingItem.IncreaseQuantity(quantity);
}
else
{
_items.Add(new OrderItem(product.Id, product.Price, quantity));
}
RecalculateTotal();
}
private void RecalculateTotal()
{
var total = _items.Sum(i => i.TotalPrice.Amount);
TotalAmount = new Money(total, "USD");
}
}
// Domain Service
public class OrderPricingService
{
public Money CalculateDiscount(Order order, Customer customer)
{
if (customer.IsVip && order.TotalAmount.Amount > 1000)
{
return new Money(order.TotalAmount.Amount * 0.1m, order.TotalAmount.Currency);
}
return new Money(0, order.TotalAmount.Currency);
}
}
پاسخ:
Clean Architecture الگوی معماری است که بر جداسازی نگرانیها و استقلال لایهها تأکید دارد تا کد قابل تست، نگهداری و انعطافپذیر باشد.
MyProject.Domain/
├── Entities/
│ ├── User.cs
│ └── Order.cs
├── ValueObjects/
│ └── Email.cs
├── Interfaces/
│ └── IUserRepository.cs
└── Services/
└── DomainService.cs
MyProject.Application/
├── UseCases/
│ ├── CreateUser/
│ │ ├── CreateUserCommand.cs
│ │ └── CreateUserHandler.cs
├── DTOs/
│ └── UserDto.cs
└── Interfaces/
└── IEmailService.cs
MyProject.Infrastructure/
├── Repositories/
│ └── UserRepository.cs
├── Services/
│ └── EmailService.cs
└── Data/
└── ApplicationDbContext.cs
MyProject.Web/
├── Controllers/
│ └── UsersController.cs
└── Program.cs
// در Program.cs
// Domain services
builder.Services.AddScoped<IDomainService, DomainService>();
// Application services
builder.Services.AddScoped<ICreateUserHandler, CreateUserHandler>();
// Infrastructure services
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IEmailService, EmailService>();
// Database
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
پاسخ:
مجموعهای از بهترین روشها برای محافظت از برنامههای ASP.NET Core در برابر حملات رایج:
// استفاده از هدرهای امنیتی
app.UseHsts();
app.UseHttpsRedirection();
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("X-Content-Type-Options", "nosniff");
context.Response.Headers.Add("Content-Security-Policy", "default-src 'self';");
await next();
});
پاسخ:
Integration Testing نوعی تست است که چندین بخش از برنامه را با هم آزمایش میکند تا از صحت تعامل آنها اطمینان حاصل شود.
WebApplicationFactory// نصب پکیج
// Microsoft.AspNetCore.Mvc.Testing
// مثال تست
public class UserControllerTests : IClassFixture<WebApplicationFactory<Program>>
{
private readonly HttpClient _client;
public UserControllerTests(WebApplicationFactory<Program> factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task Get_ReturnsSuccessAndCorrectContentType()
{
// Act
var response = await _client.GetAsync("/api/users");
// Assert
response.EnsureSuccessStatusCode(); // Status Code 200-299
Assert.Equal("application/json; charset=utf-8",
response.Content.Headers.ContentType.ToString());
}
[Fact]
public async Task GetById_WithInvalidId_ReturnsNotFound()
{
// Act
var response = await _client.GetAsync("/api/users/999");
// Assert
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
}
پاسخ:
gRPC یک فریمورک مدرن و با عملکرد بالا برای RPC (Remote Procedure Call) است که توسط گوگل توسعه داده شده.
.proto برای تعریف قرارداد استفاده میکند// تعریف سرویس در .proto
syntax = "proto3";
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
// پیادهسازی سرویس
public class GreeterService : Greeter.GreeterBase
{
public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
{
return Task.FromResult(new HelloReply
{
Message = "Hello " + request.Name
});
}
}
// استفاده از کلاینت
var channel = GrpcChannel.ForAddress("https://localhost:5001");
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "World" });
Console.WriteLine("Greeting: " + reply.Message);
پاسخ:
هر دو برای ساخت برنامههای وب در .NET استفاده میشوند، اما رویکرد متفاوتی دارند:
// کامپوننت Blazor
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
پاسخ:
.NET MAUI (.NET Multi-platform App UI) یک فریمورک کراسپلتفرم برای ساخت برنامههای دسکتاپ و موبایل با یک کدبیس واحد است.
// مثال XAML
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp.MainPage">
<StackLayout>
<Label Text="Hello, World!" FontSize="32" HorizontalOptions="Center" />
<Button Text="Click me" Clicked="OnCounterClicked" HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
// مثال C#
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
count++;
CounterLabel.Text = $"Current count: {count}";
}
}
پاسخ:
Top-level Statements یک ویژگی در C# 9+ است که امکان نوشتن کد اجرایی را بدون نیاز به متد Main و کلاس Program فراهم میکند.
using System;
namespace MyApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello, World!");
}
}
}
using System;
Console.WriteLine("Hello, World!");
// استفاده از args
if (args.Length > 0)
{
Console.WriteLine($"Hello, {args[0]}!");
}
// فراخوانی متد async
await Task.Delay(1000);
Console.WriteLine("Done!");
پاسخ:
Record یک نوع خاص از کلاس یا struct است که برای مدلسازی دادههای تغییرناپذیر (Immutable) طراحی شده.
Equals, GetHashCode, ToString// تعریف Record
public record Person(string FirstName, string LastName);
// استفاده
var person1 = new Person("John", "Doe");
var person2 = new Person("John", "Doe");
Console.WriteLine(person1); // Person { FirstName = John, LastName = Doe }
Console.WriteLine(person1 == person2); // True
// With-expression
var person3 = person1 with { LastName = "Smith" };
Console.WriteLine(person3); // Person { FirstName = John, LastName = Smith }
record struct برای Value Type های immutable تعریف کنید.
پاسخ:
Pattern Matching مجموعهای از ویژگیها در C# است که امکان بررسی ساختار دادهها را به صورت مختصر و خوانا فراهم میکند.
if (obj is string s)if (obj is Person { FirstName: "John" })case > 100:case > 0 and < 100:case Point(0, 0):// مثال با switch expression
public static decimal CalculateToll(object vehicle)
{
return vehicle switch
{
Car c => 2.00m,
Truck t when t.Weight > 5000 => 10.00m,
Truck t => 5.00m,
Bus b => 3.50m,
{ } => throw new ArgumentException("Unknown vehicle"),
null => throw new ArgumentNullException(nameof(vehicle))
};
}
// مثال با property pattern
if (order is { Customer: { IsVip: true }, TotalAmount: > 1000 })
{
ApplyDiscount(order);
}
پاسخ:
Nullable Reference Types یک ویژگی در C# 8+ است که به کامپایلر کمک میکند تا خطاهای NullReferenceException را در زمان کامپایل شناسایی کند.
// در فایل .csproj <PropertyGroup> <Nullable>enable</Nullable> </PropertyGroup> // یا در فایل کد #nullable enable
string name)? استفاده کنید (string? middleName)! به کامپایلر بگویید که یک مقدار null نیست (name!)public class User
{
public string FirstName { get; set; }
public string? MiddleName { get; set; }
public string LastName { get; set; }
public User(string firstName, string lastName)
{
FirstName = firstName;
LastName = lastName;
}
}
public void PrintUserName(User user)
{
Console.WriteLine(user.FirstName.ToUpper());
if (user.MiddleName != null)
{
Console.WriteLine(user.MiddleName.ToUpper()); // کامپایلر میداند null نیست
}
// Console.WriteLine(user.MiddleName.ToUpper()); // هشدار کامپایلر
}
پاسخ:
Source Generators یک ویژگی در کامپایلر Roslyn است که به توسعهدهندگان اجازه میدهد تا در زمان کامپایل کد C# جدیدی تولید کنند.
INotifyPropertyChanged// مثال استفاده از System.Text.Json source generator
[JsonSerializable(typeof(WeatherForecast))]
public partial class MyJsonContext : JsonSerializerContext { }
// استفاده
var forecast = new WeatherForecast { Temperature = 25 };
var json = JsonSerializer.Serialize(forecast, MyJsonContext.Default.WeatherForecast);
پاسخ:
Generic Host یک الگوی استاندارد در .NET برای پیکربندی و اجرای برنامههای غیر وبی (مانند برنامههای کنسولی، سرویسهای ویندوز) است.
// در Program.cs یک برنامه کنسولی
public class Program
{
public static async Task Main(string[] args)
{
using IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddHostedService<MyBackgroundService>();
services.AddSingleton<IMyService, MyService>();
})
.Build();
await host.RunAsync();
}
}
پاسخ:
Assembly واحد اصلی استقرار و نسخهبندی در .NET است که میتواند یک فایل .dll یا .exe باشد.
پاسخ:
GAC یک حافظه کش در سطح ماشین است که برای ذخیره assembly های به اشتراک گذاشته شده بین چندین برنامه استفاده میشود.
پاسخ:
Reflection مکانیزمی برای بازرسی و دستکاری متادیتای assembly ها، انواع، و اعضای آنها در زمان اجرا است.
// مثال استفاده از Reflection
Type myType = typeof(MyClass);
// ایجاد نمونه
object instance = Activator.CreateInstance(myType);
// فراخوانی متد
MethodInfo myMethod = myType.GetMethod("MyMethod");
myMethod.Invoke(instance, null);
// خواندن مقدار property
PropertyInfo myProperty = myType.GetProperty("MyProperty");
object value = myProperty.GetValue(instance);
پاسخ:
Attribute یک روش اعلانی برای اضافه کردن متادیتا به کد است که میتواند در زمان کامپایل یا اجرا توسط ابزارها و فریمورکها خوانده شود.
[ApiController]: مشخص میکند که یک کنترلر برای API است[Authorize]: نیاز به مجوزدهی[Required]: برای اعتبارسنجی مدل[Obsolete]: مشخص میکند که یک متد منسوخ شده[Fact]: در xUnit برای مشخص کردن یک تست// تعریف Attribute سفارشی
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyCustomAttribute : Attribute
{
public string Description { get; set; }
public MyCustomAttribute(string description)
{
Description = description;
}
}
// استفاده از Attribute
[MyCustom("This is a custom attribute")]
public class MyClass
{
[MyCustom("This is another one")]
public void MyMethod() { }
}
// خواندن Attribute با Reflection
var type = typeof(MyClass);
var attribute = (MyCustomAttribute)type.GetCustomAttribute(typeof(MyCustomAttribute));
Console.WriteLine(attribute.Description);
پاسخ:
هر دو برای پیادهسازی الگوی Publisher-Subscriber استفاده میشوند:
public delegate void MyDelegate(string message);
public class Publisher
{
public MyDelegate MyDelegateInstance;
public void DoWork()
{
MyDelegateInstance?.Invoke("Work done");
}
}
// استفاده
var publisher = new Publisher();
publisher.MyDelegateInstance = (msg) => Console.WriteLine(msg);
publisher.DoWork();
+= و -= ثبتنام کردpublic class Publisher
{
public event MyDelegate MyEvent;
public void DoWork()
{
MyEvent?.Invoke("Work done");
}
}
// استفاده
var publisher = new Publisher();
publisher.MyEvent += (msg) => Console.WriteLine(msg);
publisher.DoWork();
// publisher.MyEvent = null; // خطا! نمیتوان از خارج کلاس مقداردهی کرد
پاسخ:
Extension Methods به شما اجازه میدهند تا متدهای جدیدی به انواع داده موجود اضافه کنید بدون اینکه نیاز به تغییر کد اصلی آنها داشته باشید.
this مشخص شود// تعریف Extension Method
public static class StringExtensions
{
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' }, StringSplitOptions.RemoveEmptyEntries).Length;
}
public static string ToUrlSlug(this string value)
{
return Regex.Replace(value.ToLower(), @"[^a-z0-9_\-]+", "-").Trim("-");
}
}
// استفاده
string myString = "Hello, world! This is a test.";
int count = myString.WordCount(); // 5
string title = "My Awesome Blog Post";
string slug = title.ToUrlSlug(); // my-awesome-blog-post
Where, Select, OrderBy).
پاسخ:
کلمه کلیدی yield برای ایجاد متدهای iterator استفاده میشود که میتوانند یک دنباله را به صورت lazy تولید کنند.
// مثال تولید اعداد زوج
public static IEnumerable<int> GetEvenNumbers(int max)
{
for (int i = 0; i <= max; i += 2)
{
yield return i;
}
}
// مثال خواندن فایل خط به خط
public static IEnumerable<string> ReadLines(string filePath)
{
using (var reader = new StreamReader(filePath))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
// استفاده
foreach (var number in GetEvenNumbers(10))
{
Console.WriteLine(number);
}
foreach (var line in ReadLines("large-file.txt"))
{
// پردازش هر خط
}
پاسخ:
Global Usings یک ویژگی در C# 10+ است که به شما اجازه میدهد تا using directive ها را در یک فایل برای کل پروژه تعریف کنید.
// در یک فایل جداگانه (مثلاً Usings.cs) global using System; global using System.Collections.Generic; global using System.Linq; global using System.Threading.Tasks; global using Microsoft.AspNetCore.Mvc; global using MyProject.Models; // یا در فایل .csproj <ItemGroup> <Using Include="System.Collections.Generic" /> <Using Include="MyProject.Models" Static="true" /> </ItemGroup>
پاسخ:
File-scoped Namespaces یک ویژگی در C# 10+ است که سینتکس تعریف namespace را سادهتر میکند.
namespace MyProject.Services
{
public class MyService
{
// ...
}
}
namespace MyProject.Services;
public class MyService
{
// ...
}
پاسخ:
Memory Management در .NET توسط Garbage Collector (GC) به صورت خودکار انجام میشود.
// مثال مدیریت حافظه
public class MemoryExample
{
public void CreateObjects()
{
// اشیاء کوچک - Generation 0
var smallObject = new byte[100];
// شیء بزرگ - LOH
var largeObject = new byte[100000];
// فراخوانی دستی GC (توصیه نمیشود)
GC.Collect();
GC.WaitForPendingFinalizers();
// بررسی وضعیت حافظه
long memoryBefore = GC.GetTotalMemory(false);
Console.WriteLine($"Memory usage: {memoryBefore} bytes");
}
}
GC.Collect()، و استفاده از IDisposable برای منابع غیرمدیریت شده.
پاسخ:
IDisposable Pattern الگویی برای آزادسازی منابع غیرمدیریت شده (مانند فایل، اتصال پایگاه داده، socket) است.
public class ResourceManager : IDisposable
{
private bool disposed = false;
private FileStream fileStream; // منبع مدیریت شده
private IntPtr unmanagedResource; // منبع غیرمدیریت شده
public ResourceManager()
{
fileStream = new FileStream("temp.txt", FileMode.Create);
unmanagedResource = Marshal.AllocHGlobal(100);
}
// پیادهسازی IDisposable
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// الگوی Dispose
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// آزادسازی منابع مدیریت شده
fileStream?.Dispose();
}
// آزادسازی منابع غیرمدیریت شده
if (unmanagedResource != IntPtr.Zero)
{
Marshal.FreeHGlobal(unmanagedResource);
unmanagedResource = IntPtr.Zero;
}
disposed = true;
}
}
// Finalizer (فقط در صورت وجود منابع غیرمدیریت شده)
~ResourceManager()
{
Dispose(false);
}
}
// استفاده با using
using (var manager = new ResourceManager())
{
// استفاده از منبع
} // Dispose خودکار فراخوانی میشود
پاسخ:
Span<T> و Memory<T> انواع دادهای برای کار بهینه با بلوکهای حافظه هستند که در .NET Core 2.1+ معرفی شدند.
// مثال Span<T>
public void ProcessData()
{
int[] array = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// ایجاد Span از بخشی از آرایه
Span<int> slice = array.AsSpan(2, 5); // عناصر 3 تا 7
// تغییر مقادیر
for (int i = 0; i < slice.Length; i++)
{
slice[i] *= 2;
}
// کار با string
string text = "Hello, World!";
ReadOnlySpan<char> span = text.AsSpan(7, 5); // "World"
Console.WriteLine(span.ToString());
}
// مثال Memory<T>
public async Task ProcessDataAsync()
{
byte[] buffer = new byte[1024];
Memory<byte> memory = buffer.AsMemory();
// استفاده در عملیات async
await WriteToStreamAsync(memory);
}
public async Task WriteToStreamAsync(Memory<byte> memory)
{
using var stream = new MemoryStream();
await stream.WriteAsync(memory);
}
پاسخ:
ValueTask یک نوع value type است که برای بهینهسازی عملکرد در سناریوهای خاص async طراحی شده.
// مثال استفاده از ValueTask
public class CacheService
{
private readonly Dictionary<string, string> _cache = new();
public ValueTask<string> GetValueAsync(string key)
{
// اگر در کش موجود است، نیازی به async نیست
if (_cache.TryGetValue(key, out var cachedValue))
{
return new ValueTask<string>(cachedValue);
}
// اگر در کش نیست، از پایگاه داده بخوان
return new ValueTask<string>(LoadFromDatabaseAsync(key));
}
private async Task<string> LoadFromDatabaseAsync(string key)
{
// شبیهسازی خواندن از پایگاه داده
await Task.Delay(100);
var value = $"Value for {key}";
_cache[key] = value;
return value;
}
}
// استفاده
var service = new CacheService();
string result = await service.GetValueAsync("key1"); // اولین بار از DB
string result2 = await service.GetValueAsync("key1"); // دومین بار از cache
پاسخ:
ConfigureAwait(false) به Task میگوید که نیازی به بازگشت به context اصلی (مانند UI thread) ندارد.
// مثال deadlock در WinForms/WPF
public partial class MainForm : Form
{
private void Button_Click(object sender, EventArgs e)
{
// این کد باعث deadlock میشود
var result = GetDataAsync().Result;
// راه حل صحیح
var result2 = GetDataAsync().ConfigureAwait(false).GetAwaiter().GetResult();
}
private async Task<string> GetDataAsync()
{
await Task.Delay(1000); // بدون ConfigureAwait(false)
return "Data";
}
}
// بهترین روش در کتابخانهها
public class DataService
{
public async Task<string> GetDataAsync()
{
using var client = new HttpClient();
var response = await client.GetAsync("https://api.example.com/data")
.ConfigureAwait(false);
return await response.Content.ReadAsStringAsync()
.ConfigureAwait(false);
}
}
ConfigureAwait(false) استفاده کنید، مگر اینکه نیاز به context داشته باشید.
پاسخ:
Channels یک API برای ارتباط ناهمزمان بین producer و consumer است که جایگزین مدرن برای BlockingCollection محسوب میشود.
// مثال Producer-Consumer با Channel
public class ChannelExample
{
public async Task RunAsync()
{
// ایجاد channel محدود
var channel = Channel.CreateBounded<int>(10);
var writer = channel.Writer;
var reader = channel.Reader;
// Producer task
var producerTask = Task.Run(async () =>
{
for (int i = 0; i < 100; i++)
{
await writer.WriteAsync(i);
await Task.Delay(10);
}
writer.Complete();
});
// Consumer task
var consumerTask = Task.Run(async () =>
{
await foreach (var item in reader.ReadAllAsync())
{
Console.WriteLine($"Consumed: {item}");
await Task.Delay(50);
}
});
await Task.WhenAll(producerTask, consumerTask);
}
}
پاسخ:
IAsyncEnumerable امکان تولید و مصرف دنبالهای از دادهها به صورت ناهمزمان را فراهم میکند.
// تولید IAsyncEnumerable
public async IAsyncEnumerable<int> GenerateNumbersAsync(
int count,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
for (int i = 0; i < count; i++)
{
cancellationToken.ThrowIfCancellationRequested();
await Task.Delay(100, cancellationToken);
yield return i;
}
}
// مصرف با await foreach
public async Task ConsumeNumbersAsync()
{
await foreach (var number in GenerateNumbersAsync(10))
{
Console.WriteLine($"Received: {number}");
}
}
// مثال خواندن فایل بزرگ
public async IAsyncEnumerable<string> ReadLinesAsync(string filePath)
{
using var reader = new StreamReader(filePath);
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
yield return line;
}
}
پاسخ:
BenchmarkDotNet محبوبترین کتابخانه برای اندازهگیری دقیق عملکرد کد در .NET است.
// نصب پکیج
// BenchmarkDotNet
// مثال benchmark
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net80)]
public class StringConcatenationBenchmark
{
private const int N = 1000;
private readonly string[] _strings = Enumerable.Range(0, N).Select(i => i.ToString()).ToArray();
[Benchmark]
public string StringConcatenation()
{
string result = "";
for (int i = 0; i < N; i++)
{
result += _strings[i];
}
return result;
}
[Benchmark]
public string StringBuilderConcatenation()
{
var sb = new StringBuilder();
for (int i = 0; i < N; i++)
{
sb.Append(_strings[i]);
}
return sb.ToString();
}
[Benchmark]
public string StringJoin()
{
return string.Join("", _strings);
}
}
// اجرای benchmark
public class Program
{
public static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<StringConcatenationBenchmark>();
}
}
پاسخ:
Profiling فرآیند تحلیل عملکرد برنامه برای شناسایی bottleneck ها و بهینهسازی است.
// استفاده از DiagnosticSource برای custom profiling
public class CustomProfiler
{
private static readonly DiagnosticSource diagnosticSource =
new DiagnosticListener("MyApp.Performance");
public async Task<string> ProcessDataAsync(string data)
{
using var activity = diagnosticSource.StartActivity("ProcessData", data);
var stopwatch = Stopwatch.StartNew();
try
{
// عملیات اصلی
await Task.Delay(100);
var result = data.ToUpper();
return result;
}
finally
{
stopwatch.Stop();
diagnosticSource.Write("ProcessData.Duration", stopwatch.ElapsedMilliseconds);
}
}
}
پاسخ:
Native AOT (Ahead-of-Time) امکان کامپایل کردن برنامههای .NET به کد نیتیو را فراهم میکند.
// در فایل .csproj <PropertyGroup> <PublishAot>true</PublishAot> </PropertyGroup> // دستور publish dotnet publish -c Release
پاسخ:
Trimming فرآیند حذف کد غیرضروری از برنامه برای کاهش حجم نهایی است.
// فعالسازی trimming در .csproj
<PropertyGroup>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>link</TrimMode>
</PropertyGroup>
// حفظ کردن assembly خاص از trimming
<ItemGroup>
<TrimmerRootAssembly Include="MyLibrary" />
</ItemGroup>
// استفاده از attribute برای حفظ کد
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public class MyClass
{
// این کلاس از trimming محفوظ است
}
پاسخ:
ReadyToRun تکنولوژی pre-compilation است که بخشی از کد را قبل از استقرار کامپایل میکند تا راهاندازی سریعتر شود.
// فعالسازی R2R در .csproj <PropertyGroup> <PublishReadyToRun>true</PublishReadyToRun> </PropertyGroup> // دستور publish dotnet publish -c Release -r win-x64 --self-contained
پاسخ:
Single File Deployment امکان بستهبندی کل برنامه در یک فایل اجرایی واحد را فراهم میکند.
// فعالسازی Single File در .csproj <PropertyGroup> <PublishSingleFile>true</PublishSingleFile> <SelfContained>true</SelfContained> <RuntimeIdentifier>win-x64</RuntimeIdentifier> </PropertyGroup> // دستور publish dotnet publish -c Release
پاسخ:
.NET Standard یک مشخصات (specification) است که API های مشترک بین تمام پیادهسازیهای .NET را تعریف میکند.
// تعریف کتابخانه .NET Standard <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> </PropertyGroup>
پاسخ:
TFM یک شناسه استاندارد برای مشخص کردن نسخه و نوع فریمورک .NET است.
net8.0: .NET 8net6.0: .NET 6net48: .NET Framework 4.8netstandard2.0: .NET Standard 2.0net8.0-android: .NET 8 برای Android// Multi-targeting در .csproj
<PropertyGroup>
<TargetFrameworks>net6.0;net8.0;net48</TargetFrameworks>
</PropertyGroup>
// Conditional compilation
#if NET8_0_OR_GREATER
// کد مخصوص .NET 8+
#elif NET48
// کد مخصوص .NET Framework 4.8
#endif
پاسخ:
دو روش مختلف برای اضافه کردن وابستگیها به پروژه:
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
<ProjectReference Include="..\MyLibrary\MyLibrary.csproj" /> <ProjectReference Include="..\Common\Common.csproj" />
پاسخ:
NuGet مدیر پکیج رسمی .NET است که امکان اشتراکگذاری و استفاده از کتابخانهها را فراهم میکند.
// نصب پکیج dotnet add package Newtonsoft.Json // حذف پکیج dotnet remove package Newtonsoft.Json // بهروزرسانی پکیجها dotnet restore // لیست پکیجهای نصب شده dotnet list package // جستجوی پکیج dotnet search EntityFramework
// در .csproj <PropertyGroup> <PackageId>MyAwesomeLibrary</PackageId> <Version>1.0.0</Version> <Authors>Your Name</Authors> <Description>A great library for doing awesome things</Description> <PackageLicenseExpression>MIT</PackageLicenseExpression> </PropertyGroup> // ساخت پکیج dotnet pack -c Release // انتشار پکیج dotnet nuget push MyAwesomeLibrary.1.0.0.nupkg --api-key YOUR_API_KEY --source https://api.nuget.org/v3/index.json
پاسخ:
Global Tools برنامههای کنسولی هستند که به صورت سراسری در سیستم نصب میشوند و از هر جایی قابل اجرا هستند.
// نصب global tool dotnet tool install -g dotnet-ef // لیست global tools نصب شده dotnet tool list -g // بهروزرسانی global tool dotnet tool update -g dotnet-ef // حذف global tool dotnet tool uninstall -g dotnet-ef
// در .csproj
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<PackAsTool>true</PackAsTool>
<ToolCommandName>mytool</ToolCommandName>
<PackageId>MyGlobalTool</PackageId>
</PropertyGroup>
// Program.cs
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Hello from my global tool!");
}
}
dotnet-ef، dotnet-aspnet-codegenerator، dotnet-outdated
پاسخ:
Workloads مجموعهای از ابزارها و SDK های اضافی هستند که برای توسعه انواع خاصی از برنامهها نصب میشوند.
// مشاهده workloads نصب شده dotnet workload list // نصب workload dotnet workload install maui // بهروزرسانی workloads dotnet workload update // حذف workload dotnet workload uninstall maui // بازیابی workloads از روی پروژه dotnet workload restore
پاسخ:
.NET CLI (Command Line Interface) مجموعهای از ابزارهای خط فرمان برای توسعه، ساخت، اجرا، و انتشار برنامههای .NET است.
// ایجاد پروژه جدید dotnet new console -n MyApp dotnet new webapi -n MyApi dotnet new classlib -n MyLibrary // اجرای پروژه dotnet run dotnet run --project MyApp // ساخت پروژه dotnet build dotnet build -c Release // تست پروژه dotnet test dotnet test --logger trx // انتشار پروژه dotnet publish -c Release -o ./publish // اضافه کردن پکیج dotnet add package Newtonsoft.Json // مدیریت solution dotnet sln add MyProject.csproj dotnet sln list
// مشاهده اطلاعات .NET dotnet --info dotnet --list-sdks dotnet --list-runtimes // پاکسازی dotnet clean dotnet nuget locals all --clear // فرمت کردن کد dotnet format // تحلیل کد dotnet analyze
پاسخ:
DevOps و CI/CD در .NET شامل اتوماسیون فرآیند ساخت، تست، و استقرار برنامهها است.
// مثال GitHub Actions workflow
name: .NET CI/CD
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup .NET
uses: actions/setup-dotnet@v3
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal
- name: Publish
run: dotnet publish -c Release -o ./publish
- name: Deploy to Azure
uses: azure/webapps-deploy@v2
with:
app-name: 'my-app'
publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}
package: './publish'
پاسخ:
Monitoring و Observability شامل ابزارها و تکنیکهایی برای نظارت بر سلامت و عملکرد برنامههای .NET است.
// پیکربندی Logging در Program.cs
builder.Logging.ClearProviders();
builder.Logging.AddConsole();
builder.Logging.AddApplicationInsights();
// استفاده از ILogger
public class OrderService
{
private readonly ILogger<OrderService> _logger;
public OrderService(ILogger<OrderService> logger)
{
_logger = logger;
}
public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
{
_logger.LogInformation("Creating order for customer {CustomerId}", request.CustomerId);
try
{
var order = new Order { CustomerId = request.CustomerId };
await _repository.SaveAsync(order);
_logger.LogInformation("Order {OrderId} created successfully", order.Id);
return order;
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to create order for customer {CustomerId}", request.CustomerId);
throw;
}
}
}
// Custom Metrics با System.Diagnostics.Metrics
public class OrderMetrics
{
private static readonly Meter Meter = new("MyApp.Orders");
private static readonly Counter<int> OrdersCreated = Meter.CreateCounter<int>("orders_created_total");
private static readonly Histogram<double> OrderProcessingTime = Meter.CreateHistogram<double>("order_processing_duration_ms");
public void RecordOrderCreated()
{
OrdersCreated.Add(1);
}
public void RecordProcessingTime(double milliseconds)
{
OrderProcessingTime.Record(milliseconds);
}
}
پاسخ:
فرآیند شناسایی و مدیریت آسیبپذیریهای امنیتی در برنامههای .NET:
// بررسی آسیبپذیریها dotnet list package --vulnerable // بهروزرسانی پکیجهای آسیبپذیر dotnet add package PackageName --version LatestSecureVersion // فعالسازی NuGet audit در .csproj <PropertyGroup> <NuGetAudit>true</NuGetAudit> <NuGetAuditMode>all</NuGetAuditMode> </PropertyGroup>
پاسخ:
ابزارها و تکنیکهایی برای بهبود کیفیت کد و شناسایی مشکلات بدون اجرای برنامه:
// فعالسازی Code Analysis در .csproj
<PropertyGroup>
<EnableNETAnalyzers>true</EnableNETAnalyzers>
<AnalysisLevel>latest</AnalysisLevel>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="9.0.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
// فایل .editorconfig برای قوانین استایل
root = true
[*.cs]
dotnet_analyzer_diagnostic.CA1001.severity = error
dotnet_analyzer_diagnostic.CA1816.severity = warning
پاسخ:
تولید مستندات خودکار از کد و کامنتهای XML:
/// <summary>
/// محاسبه مجموع دو عدد
/// </summary>
/// <param name="a">عدد اول</param>
/// <param name="b">عدد دوم</param>
/// <returns>مجموع دو عدد</returns>
/// <exception cref="ArgumentException">زمانی که ورودیها نامعتبر باشند</exception>
public int Add(int a, int b)
{
if (a < 0 || b < 0)
throw new ArgumentException("Numbers must be positive");
return a + b;
}
// فعالسازی XML Documentation در .csproj
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DocumentationFile>bin\$(Configuration)\$(TargetFramework)\$(AssemblyName).xml</DocumentationFile>
</PropertyGroup>
// استفاده از Swagger/OpenAPI برای API Documentation
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
// اضافه کردن XML comments به Swagger
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
پاسخ:
فرآیند آمادهسازی برنامه برای پشتیبانی از زبانها و فرهنگهای مختلف:
// در Program.cs
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[] { "en-US", "fa-IR", "ar-SA" };
options.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
});
var app = builder.Build();
app.UseRequestLocalization();
// استفاده از IStringLocalizer
public class HomeController : Controller
{
private readonly IStringLocalizer<HomeController> _localizer;
public HomeController(IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}
public IActionResult Index()
{
ViewData["Message"] = _localizer["Welcome"];
return View();
}
}
// Resources/Controllers.HomeController.en-US.resx Welcome = "Welcome to our website" // Resources/Controllers.HomeController.fa-IR.resx Welcome = "به وبسایت ما خوش آمدید"
پاسخ:
سیستم پیکربندی .NET امکان مدیریت تنظیمات برنامه از منابع مختلف را فراهم میکند:
// appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyApp;Trusted_Connection=true;"
},
"Logging": {
"LogLevel": {
"Default": "Information"
}
},
"MySettings": {
"ApiKey": "your-api-key",
"MaxRetries": 3
}
}
// تعریف کلاس Options
public class MySettings
{
public string ApiKey { get; set; }
public int MaxRetries { get; set; }
}
// ثبت در DI
builder.Services.Configure<MySettings>(builder.Configuration.GetSection("MySettings"));
// استفاده در سرویس
public class MyService
{
private readonly MySettings _settings;
public MyService(IOptions<MySettings> options)
{
_settings = options.Value;
}
public async Task DoWorkAsync()
{
// استفاده از _settings.ApiKey و _settings.MaxRetries
}
}
پاسخ:
مدیریت محیطهای مختلف توسعه، تست، و تولید:
// تشخیص محیط در کد
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
if (env.IsProduction())
{
// تنظیمات مخصوص تولید
}
}
// تنظیم متغیر محیطی
// Windows
set ASPNETCORE_ENVIRONMENT=Production
// Linux/Mac
export ASPNETCORE_ENVIRONMENT=Production
// در launchSettings.json
{
"profiles": {
"Development": {
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
پاسخ:
تست عملکرد برای اندازهگیری پاسخگویی، پایداری، و مقیاسپذیری برنامه:
// استفاده از NBomber برای Load Testing
var scenario = Scenario.Create("api_test", async context =>
{
using var client = new HttpClient();
var response = await client.GetAsync("https://localhost:5001/api/products");
return response.IsSuccessStatusCode ? Response.Ok() : Response.Fail();
})
.WithLoadSimulations(
Simulation.InjectPerSec(rate: 100, during: TimeSpan.FromMinutes(5))
);
NBomberRunner
.RegisterScenarios(scenario)
.Run();
// مثال Benchmark با BenchmarkDotNet
[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net80)]
public class ApiPerformanceBenchmark
{
private HttpClient _client;
[GlobalSetup]
public void Setup()
{
_client = new HttpClient();
}
[Benchmark]
public async Task<string> GetProducts()
{
var response = await _client.GetAsync("https://localhost:5001/api/products");
return await response.Content.ReadAsStringAsync();
}
[GlobalCleanup]
public void Cleanup()
{
_client?.Dispose();
}
}
پاسخ:
آینده .NET شامل بهبودهای مداوم در عملکرد، ابزارهای توسعه، و پشتیبانی از تکنولوژیهای نوین است:
// استفاده از Primary Constructors (C# 12)
public class UserService(IUserRepository repository, ILogger<UserService> logger)
{
public async Task<User> GetUserAsync(int id)
{
logger.LogInformation("Getting user {UserId}", id);
return await repository.GetByIdAsync(id);
}
}
// استفاده از Collection expressions (C# 12)
int[] numbers = [1, 2, 3, 4, 5];
List<string> names = ["Alice", "Bob", "Charlie"];
// استفاده از Required members (C# 11)
public class User
{
public required string Name { get; init; }
public required string Email { get; init; }
public string? PhoneNumber { get; init; }
}