Intha guide-la Swashbuckle (Swagger), Image Upload, mariyum Full CRUD (Create, Read, Update, Delete) ellam step-by-step cover pannirukom. Update/Delete panrapo pazhaya image-a server-la irundhu automatic-a delete panra logic-um irukku — real-time projects-ku romba mukkiyam.
📁 Final Project Folder Structure
MyCrudApp/
│
├── Controllers/
│ └── ProductController.cs
│
├── Data/
│ └── AppDbContext.cs
│
├── Models/
│ ├── Product.cs
│ └── ProductDto.cs
│
├── Migrations/ 👈 (dotnet ef migrations add ku apram auto-generate aagum)
│
├── wwwroot/
│ └── uploads/ 👈 (uploaded images ithula store aagum)
│
├── appsettings.json
├── appsettings.Development.json
├── Program.cs
└── MyCrudApp.csproj
Step 1: Project & Packages Setup
dotnet new webapi -n MyCrudApp
cd MyCrudApp
dotnet add package Microsoft.EntityFrameworkCore.SqlServer
dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet add package Microsoft.EntityFrameworkCore.Design
dotnet add package Swashbuckle.AspNetCore
Designpackage illama,dotnet ef migrations addcommand work aagathu — idhu miss pannama add pannunga.
Step 2: Models (Models/Product.cs)
namespace MyCrudApp.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
public string ImageUrl { get; set; }
}
}
Models/ProductDto.cs (Request Model with File)
using Microsoft.AspNetCore.Http;
namespace MyCrudApp.Models
{
public class ProductDto
{
public string Name { get; set; }
public string Description { get; set; }
public string Category { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
public IFormFile? ImageFile { get; set; } // '?' na Optional (updates ku)
}
}
Step 3: Data/AppDbContext.cs (Missing piece — idhu illama app run aagathu)
using Microsoft.EntityFrameworkCore;
using MyCrudApp.Models;
namespace MyCrudApp.Data
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
}
}
Step 4: appsettings.json (Connection String add pannunga)
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyCrudAppDb;Trusted_Connection=True;TrustServerCertificate=True;"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
Local-la SQL Server illana,
Server=localhostku pathila unga SQL Server instance name podunga (e.g.Server=.\\SQLEXPRESS). SQL auth use panra pakshathulaUser Id=sa;Password=YourPassword;nu maathi podunga.
Step 5: Program.cs (Swagger & Static Files Setup)
using Microsoft.EntityFrameworkCore;
using MyCrudApp.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
// Swagger (Swashbuckle) Setup
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Swagger UI Enable panrom
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseStaticFiles(); // Image url browser-la view panna must
app.UseAuthorization();
app.MapControllers();
app.Run();
Step 6: The Ultimate CRUD Controller (Controllers/ProductController.cs)
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyCrudApp.Data;
using MyCrudApp.Models;
namespace MyCrudApp.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
private readonly AppDbContext _context;
private readonly IWebHostEnvironment _env;
public ProductController(AppDbContext context, IWebHostEnvironment env)
{
_context = context;
_env = env;
}
// 1. CREATE (POST)
[HttpPost]
public async Task<IActionResult> CreateProduct([FromForm] ProductDto dto)
{
string imageUrl = "";
if (dto.ImageFile != null && dto.ImageFile.Length > 0)
{
imageUrl = await SaveImage(dto.ImageFile);
}
var product = new Product
{
Name = dto.Name,
Description = dto.Description,
Category = dto.Category,
Price = dto.Price,
StockQuantity = dto.StockQuantity,
ImageUrl = imageUrl
};
_context.Products.Add(product);
await _context.SaveChangesAsync();
return Ok(product);
}
// 2. READ ALL (GET)
[HttpGet]
public async Task<IActionResult> GetProducts()
{
return Ok(await _context.Products.ToListAsync());
}
// 2.1 READ BY ID (GET)
[HttpGet("{id}")]
public async Task<IActionResult> GetProduct(int id)
{
var product = await _context.Products.FindAsync(id);
if (product == null) return NotFound();
return Ok(product);
}
// 3. UPDATE (PUT)
[HttpPut("{id}")]
public async Task<IActionResult> UpdateProduct(int id, [FromForm] ProductDto dto)
{
var product = await _context.Products.FindAsync(id);
if (product == null) return NotFound();
// Puthu image anuppi irundha, pazhaya image-a delete panni puthusa save pannanum
if (dto.ImageFile != null && dto.ImageFile.Length > 0)
{
DeleteImage(product.ImageUrl);
product.ImageUrl = await SaveImage(dto.ImageFile);
}
product.Name = dto.Name;
product.Description = dto.Description;
product.Category = dto.Category;
product.Price = dto.Price;
product.StockQuantity = dto.StockQuantity;
await _context.SaveChangesAsync();
return Ok(product);
}
// 4. DELETE (DELETE)
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteProduct(int id)
{
var product = await _context.Products.FindAsync(id);
if (product == null) return NotFound();
// Database-la data delete aaga munnadi, server folder-la irundhu image-a delete panrom
DeleteImage(product.ImageUrl);
_context.Products.Remove(product);
await _context.SaveChangesAsync();
return Ok(new { message = "Product and Image deleted successfully!" });
}
// --- Helper Methods ---
private async Task<string> SaveImage(IFormFile file)
{
var uploadsFolder = Path.Combine(_env.WebRootPath, "uploads");
if (!Directory.Exists(uploadsFolder)) Directory.CreateDirectory(uploadsFolder);
var uniqueFileName = Guid.NewGuid().ToString() + "_" + file.FileName;
var filePath = Path.Combine(uploadsFolder, uniqueFileName);
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream);
}
return $"{Request.Scheme}://{Request.Host}/uploads/{uniqueFileName}";
}
private void DeleteImage(string imageUrl)
{
if (string.IsNullOrEmpty(imageUrl)) return;
var fileName = Path.GetFileName(new Uri(imageUrl).LocalPath);
var filePath = Path.Combine(_env.WebRootPath, "uploads", fileName);
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
}
}
}
Step 7: Database Create Panra Steps (Migration)
Controller and DbContext ready aana apparam, database-a physically create pannanum:
dotnet ef migrations add InitialCreate
dotnet ef database update
Idhu run panna apparam, Products table unga SQL Server database-la automatic-a create aagidum.
wwwroot/uploadsfolder-a manually create panni vachikonga (illana git-la empty folder track aagathu — venumna.gitkeepfile podunga).
Step 8: Swagger-la Test Panra Steps
App-a run pannitu (dotnet run), browser-la http://localhost:<port>/swagger open pannunga.
CREATE (POST)
POST /api/Product → Try it out → Fields fill pannunga → Image choose pannunga → Execute. Data save aagum.
READ (GET)
GET /api/Product → Try it out → Execute. Save aana ella data-vum JSON format-la varum. Athula irukka id-a note panni vachikonga.
UPDATE (PUT)
PUT /api/Product/{id} → Try it out → Note panna id-a mela enter pannunga. Kela form-la details-a maathi (e.g., Price increase pannunga), vera puthu image select pannitu → Execute. Ippo paathingana pazhaya image unga local folder-la irundhu automatic-a delete aagi puthu image vanthurukum!
DELETE (DELETE)
DELETE /api/Product/{id} → Try it out → id enter panni Execute. Database-la irundhu data-vum poidum, unga wwwroot/uploads folder-la irundhu antha specific image-um delete aagidum.
🧠 Quick Recap (Article-ku Highlights)
- ✅ Swagger UI auto-generated API docs
- ✅
IFormFilemூlam multipart/form-data image upload - ✅ EF Core Code-First approach with Migrations
- ✅ Old image cleanup logic on Update & Delete
- ✅ Clean separation: Models / DTOs / Data / Controllers
Intha structure follow pannina, unga dev.to article production-ready backend guide-a maarum. All the best! 🚀
Top comments (0)