ASP.NET Core Backend — সম্পূর্ণ ব্যাখ্যা (Zero থেকে)
আগে দেখো এই backend এ 2টা class আছে। এরা কীভাবে একসাথে কাজ করে:
Angular (Frontend)
│
│ HTTP Request
▼
ImagesController ← দরজা (Request receive করে)
│
│ কাজ delegate করে
▼
ImageRepository ← কারখানা (আসল কাজ করে)
│
├──▶ File System (image save করে wwwroot/images তে)
│
└──▶ Database (image info save করে)
Analogy: Controller হলো হোটেলের রিসেপশন — guest কে receive করে, কাজ অন্যকে দেয়। Repository হলো হোটেলের ম্যানেজার — আসল কাজ সে করে।
🏗️ PART 1 — ImageRepository (কারখানা)
Step 1.1 — Constructor & Dependency Injection
public class ImageRepository
{
private readonly BlogDbContext dbContext;
private readonly IWebHostEnvironment env;
private readonly IHttpContextAccessor httpContextAccessor;
public ImageRepository(BlogDbContext dbContext,
IWebHostEnvironment env,
IHttpContextAccessor httpContextAccessor)
{
this.dbContext = dbContext;
this.env = env;
this.httpContextAccessor = httpContextAccessor;
}
}
3টা জিনিস inject হচ্ছে:
| Dependency | কী করে | Real Example |
|---|---|---|
BlogDbContext | Database এর সাথে কথা বলে | dbContext.BlogImages.AddAsync() |
IWebHostEnvironment | Server এর folder path জানে | env.WebRootPath → "C:/project/wwwroot" |
IHttpContextAccessor | Current HTTP request এর info দেয় | Scheme, Host জানার জন্য |
Dependency Injection কী?
// ❌ পুরনো way — নিজে object বানানো (tight coupling)
var env = new WebHostEnvironment(); // এভাবে করা যায় না, ভুল
// ✅ DI way — Angular এর মতোই, ASP.NET নিজে inject করে
public ImageRepository(IWebHostEnvironment env) // ASP.NET বলছে "আমি দেবো"
Analogy: তুমি রান্না করবে, কিন্তু বাজার থেকে মাল আনবে না — কেউ এনে দেবে। DI হলো সেই মাল এনে দেওয়ার system।
Step 1.2 — UploadAsync() Method — ধাপে ধাপে
public async Task<BlogImage> UploadAsync(ImageUploadRequestDto request)
async Task<BlogImage> মানে — এই method async (অপেক্ষা করতে পারবে) এবং শেষে একটা BlogImage object return করবে।
🔹 ধাপ 1 — File Extension বের করা
var extension = Path.GetExtension(request.File.FileName);
var fileName = $"{Guid.NewGuid()}{extension}";
Example:
request.File.FileName = "my-photo.jpg"
Path.GetExtension("my-photo.jpg") = ".jpg"
Guid.NewGuid() = "a3f8c2d1-4b5e-..." (random unique ID)
fileName = "a3f8c2d1-4b5e-....jpg"
কেন Guid? User যদি দুইজন একই নামের file upload করে — conflict হবে। Guid দিয়ে প্রতিটা file কে unique name দেওয়া হচ্ছে।
Analogy: দুইজনের নাম “Navid” হতে পারে, কিন্তু Student ID (22-46956-1) সবসময় unique — Guid হলো সেই Student ID।
🔹 ধাপ 2 — File Save করার Path বানানো
var localPath = Path.Combine(env.WebRootPath, "images", fileName);
Example:
env.WebRootPath = "C:/MyProject/wwwroot"
fileName = "a3f8c2d1.jpg"
localPath = "C:/MyProject/wwwroot/images/a3f8c2d1.jpg"
Path.Combine() ব্যবহার করা হয় কারণ Windows এ \ আর Linux এ / — Path.Combine সেটা নিজেই handle করে।
🔹 ধাপ 3 — Folder তৈরি করা (না থাকলে)
if (!Directory.Exists(Path.Combine(env.WebRootPath, "images")))
{
Directory.CreateDirectory(Path.Combine(env.WebRootPath, "images"));
}
কেন? প্রথমবার upload এর সময় wwwroot/images folder নাও থাকতে পারে। না থাকলে file save করতে গেলে error হবে। তাই আগে folder আছে কিনা check করো, না থাকলে বানাও।
wwwroot/
├── css/
├── js/
└── images/ ← এই folder না থাকলে এখানে বানানো হচ্ছে
🔹 ধাপ 4 — File Disk এ Save করা
using (var stream = new FileStream(localPath, FileMode.Create))
{
await request.File.CopyToAsync(stream);
}
এটা কীভাবে কাজ করে?
request.File (memory তে আছে, Angular থেকে আসা)
│
│ CopyToAsync()
▼
FileStream (disk এ write করার channel)
│
▼
"C:/MyProject/wwwroot/images/a3f8c2d1.jpg" ← disk এ save হলো
using block কেন? File stream use শেষে automatically close হয়ে যাবে — memory leak হবে না।
Analogy: পানির পাইপ খুললে কাজ শেষে বন্ধ করতে হয়।
usingহলো সেই automatic পাইপ বন্ধ করার system।
🔹 ধাপ 5 — Public URL বানানো
var httpRequest = httpContextAccessor.HttpContext.Request;
var url = $"{httpRequest.Scheme}://{httpRequest.Host}/images/{fileName}";
Example:
httpRequest.Scheme = "https"
httpRequest.Host = "localhost:5001"
fileName = "a3f8c2d1.jpg"
url = "https://localhost:5001/images/a3f8c2d1.jpg"
কেন HttpContextAccessor দিয়ে? Development এ localhost:5001, production এ myblog.com — hardcode না করে runtime এ dynamically বানানো হচ্ছে।
এই URL টাই Angular এ দেখাবে <img [src]="..."> তে।
🔹 ধাপ 6 — Database এ Save করা
var blogImage = new BlogImage
{
Id = Guid.NewGuid(),
FileName = fileName, // "a3f8c2d1.jpg"
Title = request.Title, // "My Banner"
FileExtension = extension, // ".jpg"
FileSizeInBytes = request.File.Length, // 204800 (bytes)
Url = url // "https://localhost:5001/images/a3f8c2d1.jpg"
};
await dbContext.BlogImages.AddAsync(blogImage);
await dbContext.SaveChangesAsync();
return blogImage;
Database এ কী save হচ্ছে:
BlogImages Table:
┌──────────────────┬───────────────┬───────────────┬──────────────────────────────────────┐
│ Id │ FileName │ Title │ Url │
├──────────────────┼───────────────┼───────────────┼──────────────────────────────────────┤
│ b2c3-d4e5-... │ a3f8c2d1.jpg │ My Banner │ https://localhost:5001/images/a3f8.. │
└──────────────────┴───────────────┴───────────────┴──────────────────────────────────────┘
File system এ কী save হচ্ছে:
wwwroot/images/a3f8c2d1.jpg ← actual image file
⚠️ Important: Database এ actual image নেই — শুধু URL আছে। Image আছে disk এ। DB শুধু “ঠিকানা” রাখে।
Step 1.3 — GetAllAsync() Method
public async Task<List<BlogImage>> GetAllAsync()
{
return await dbContext.BlogImages.ToListAsync();
}
এটা simple — Database এর BlogImages table এর সব row নিয়ে List বানিয়ে return করে।
Database → সব BlogImage rows → List<BlogImage> → Controller → Angular
🚪 PART 2 — ImagesController (দরজা)
Step 2.1 — Controller Setup
[Route("api/[controller]")] // → "api/images"
[ApiController]
public class ImagesController : ControllerBase
{
private readonly ImageRepository imageRepository;
public ImagesController(ImageRepository imageRepository)
{
this.imageRepository = imageRepository; // DI দিয়ে repository inject
}
}
[Route("api/[controller]")] — [controller] মানে class name থেকে “Controller” বাদ দিলে যা থাকে = "images"। তাই full route হয় api/images।
Step 2.2 — Upload Endpoint
[HttpPost("upload")] // → POST api/images/upload
public async Task<IActionResult> Upload([FromForm] ImageUploadRequestDto request)
{
if (request.File == null || request.File.Length == 0)
return BadRequest("No file"); // 400 error
var image = await imageRepository.UploadAsync(request);
return Ok(image.Url); // 200 + URL string
}
[FromForm] কেন? Angular থেকে FormData আসছে (multipart/form-data)। [FromForm] বলছে — “JSON না, form data থেকে read করো।”
Response:
✅ Success → HTTP 200 → "https://localhost:5001/images/a3f8c2d1.jpg"
❌ No file → HTTP 400 → "No file"
Step 2.3 — Gallery Endpoint
[HttpGet] // → GET api/images
public async Task<IActionResult> GetAll()
{
var images = await imageRepository.GetAllAsync();
return Ok(images);
}
Response:
HTTP 200 →
[
{ "id": "b2c3...", "url": "https://...jpg", "title": "Banner", ... },
{ "id": "d4e5...", "url": "https://...png", "title": "Photo", ... }
]
🔄 Complete End-to-End Flow
Upload Flow:
Angular: imageService.upload(file, name, title)
│ POST api/images/upload (FormData)
▼
ImagesController.Upload()
│ validation check
▼
ImageRepository.UploadAsync()
│
├── Guid দিয়ে unique fileName বানাও
├── wwwroot/images/ folder check/create
├── FileStream দিয়ে disk এ save করো
├── URL বানাও (scheme + host + path)
└── DB তে BlogImage save করো
│
▼
Controller → return Ok(image.Url)
│ "https://localhost:5001/images/a3f8c2d1.jpg"
▼
Angular: imageSelected.emit(url) → Parent এ URL পাঠায়
Gallery Load Flow:
Angular: imageService.getAll()
│ GET api/images
▼
ImagesController.GetAll()
│
▼
ImageRepository.GetAllAsync()
│ dbContext.BlogImages.ToListAsync()
▼
Database → সব rows
│
▼
Controller → return Ok(images) [JSON array]
│
▼
Angular: images.set(res) → Signal update → Gallery render
🧠 Key Concepts Summary
| Concept | কী করে | Example |
|---|---|---|
| Repository Pattern | DB logic আলাদা রাখে | ImageRepository |
| Dependency Injection | Object ASP.NET নিজে দেয় | Constructor এ inject |
[FromForm] | FormData parse করে | File upload এর জন্য |
Guid.NewGuid() | Unique ID/filename বানায় | Collision এড়াতে |
IWebHostEnvironment | Server path জানে | wwwroot path পেতে |
FileStream | Disk এ file write করে | Image save করতে |
IHttpContextAccessor | Runtime এ URL বানায় | Hardcode এড়াতে |
async/await | Block না করে অপেক্ষা করে | DB/File I/O তে |
এই pattern টা বুঝলে যেকোনো ASP.NET Core project এ file upload system বানাতে পারবে!