پاسخ:
.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
, JsonResult
public 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.0
X-Version: 1.0
Accept: 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; } }