Aspect .NET Core .NET Framework
Platform Cross-platform (Windows, Linux, macOS) Windows only
Source Open source Mostly closed source
Performance Better, optimized runtime Legacy
Modularity Package-based (NuGet) Full framework
CLI Full CLI support Limited
Side-by-side Multiple versions Single version per machine
Use case Modern apps, microservices Legacy Windows apps
Hỗ trợ Views (Razor pages)
Phù hợp cho web applications với UI
Convention-based routing
Model binding đầy đủ
ViewBag, ViewData
public class HomeController : Controller
{
public IActionResult Index()
{
ViewData["Title"] = "Home";
return View();
}
}
RESTful services, JSON/XML
Không có Views
Attribute routing
Content negotiation
[ApiController] attribute
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok();
}
Rút gọn code
Không cần Controller
Top-level statements
Phù hợp cho microservices
Lambda expressions
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/products", () => Results.Ok(new { name = "Product" }));
app.Run();
Feature MVC Web API Minimal API
Views ✅ Yes ❌ No ❌ No
Controllers ✅ Yes ✅ Yes ❌ No
Routing Convention + Attribute Attribute MapGet/MapPost
Model Binding Full Full Limited
Testability Medium Medium High
Use case Web apps APIs Microservices
public abstract class Animal
{
public string Name { get; set; }
// Abstract method - phải implement
public abstract void MakeSound();
// Virtual method - có thể override
public virtual void Sleep()
{
Console.WriteLine("Sleeping...");
}
// Non-abstract method
public void Eat()
{
Console.WriteLine("Eating...");
}
}
public class Dog : Animal
{
public override void MakeSound()
{
Console.WriteLine("Woof!");
}
}
public interface IAnimal
{
string Name { get; set; }
void MakeSound();
}
public interface IFlyable
{
void Fly();
}
public interface IPlayable
{
void Play();
}
Aspect Abstract Class Interface
Multiple inheritance ❌ No ✅ Yes
Constructor ✅ Yes ❌ No
Fields ✅ Yes ❌ No (properties only)
Access modifiers ✅ Yes ❌ No (public implicit)
Default implementation ✅ Yes ✅ Yes (C# 8+)
State ✅ Can have ❌ No
Inheritance Single Multiple
Use case “is-a” relationship “can-do” capability
public IEnumerable<Product> GetProducts()
{
return _context.Products; // Local collection
}
foreach (var product in GetProducts())
{
// Process
}
Thực thi trên client
Toàn bộ data được load vào memory trước khi filter
Phù hợp cho small datasets hoặc in-memory data
public IQueryable<Product> GetProducts()
{
return _context.Products; // Query provider
}
var results = GetProducts()
.Where(p => p.Price > 100)
.OrderBy(p => p.Name);
// Query được translate sang SQL và execute trên database
Thực thi trên database
Query được build và translate sang SQL
Phù hợp cho large datasets và remote data sources
Aspect IEnumerable IQueryable
Location Client-side Server-side
Execution In-memory Database query
SQL Translation ❌ No ✅ Yes
Deferred Yes Yes
Use case In-memory collections Database queries
Performance Slow with large data Optimized
// ✅ IEnumerable - Khi đã có data trong memory
var numbers = new List<int> { 1, 2, 3, 4, 5 };
var evens = numbers.Where(n => n % 2 == 0);
// ✅ IQueryable - Khi query database
var products = _context.Products
.Where(p => p.Price > 100)
.OrderBy(p => p.Name);
// ❌ Tránh - IEnumerable từ database
var products = _context.Products.ToList()
.Where(p => p.Price > 100); // Load all, then filter
Aspect vardynamic
Type checking Compile-time Runtime
IntelliSense ✅ Yes ❌ No
Performance Fast Slower
Use case Type known at compile Late binding
Aspect constreadonly
Evaluation Compile-time Runtime
Value Must be known at compile Set at runtime
Static Always static Can be instance-level
Use case Compile-time constants Runtime constants
Aspect stringStringBuilder
Type Immutable Mutable
Memory New allocation per change Dynamic buffer
Use case Small strings, no changes Large strings, many concatenations
// ❌ Sequential - Chậm
foreach (var url in urls)
{
var response = await httpClient.GetAsync(url);
}
// ✅ Parallel - Nhanh hơn
var tasks = urls.Select(url => httpClient.GetAsync(url));
var responses = await Task.WhenAll(tasks);