🔥 Super, Sathish! You’ve completed Day 3 beautifully — now we’ll move to
📅 DAY 4 — Service + Controller Setup (User & Role API)
This is the day your project becomes alive — you’ll be able to open Swagger and call /api/users to see data from PostgreSQL 🚀
🎯 Goal
Connect database → repositories → services → controllers → Swagger test.
We’ll implement User + Role modules fully.
🧩 Project Path Summary
| Layer | Folder | Purpose |
|---|---|---|
| Domain | Accounting.Domain/Entities |
Entity classes |
| Infrastructure | Accounting.Infrastructure/Repositories |
DB access |
| API |
Accounting.API/Controllers, Accounting.API/Services
|
Web API endpoints |
🧠 DAY 4 Steps
Step 1 – Create Service Interfaces
📁 Accounting.API/Services/Interfaces/IUserService.cs
using Accounting.Core.Entities;
namespace Accounting.API.Services.Interfaces
{
public interface IUserService
{
Task<IEnumerable<User>> GetAllAsync();
Task<User?> GetByIdAsync(int id);
Task<User> CreateAsync(User user);
}
}
📁 Accounting.API/Services/Interfaces/IRoleService.cs
using Accounting.Core.Entities;
namespace Accounting.API.Services.Interfaces
{
public interface IRoleService
{
Task<IEnumerable<Role>> GetAllAsync();
}
}
Step 2 – Implement the Services
📁 Accounting.API/Services/Implementations/UserService.cs
using Accounting.Core.Entities;
using Accounting.Infrastructure.Repositories.Interfaces;
using Accounting.API.Services.Interfaces;
namespace Accounting.API.Services.Implementations
{
public class UserService : IUserService
{
private readonly IGenericRepository<User> _userRepo;
private readonly IUnitOfWork _uow;
public UserService(IGenericRepository<User> userRepo, IUnitOfWork uow)
{
_userRepo = userRepo;
_uow = uow;
}
public async Task<IEnumerable<User>> GetAllAsync() => await _userRepo.GetAllAsync();
public async Task<User?> GetByIdAsync(int id) => await _userRepo.GetByIdAsync(id);
public async Task<User> CreateAsync(User user)
{
await _userRepo.AddAsync(user);
await _uow.SaveChangesAsync();
return user;
}
}
}
📁 Accounting.API/Services/Implementations/RoleService.cs
using Accounting.Core.Entities;
using Accounting.Infrastructure.Repositories.Interfaces;
using Accounting.API.Services.Interfaces;
namespace Accounting.API.Services.Implementations
{
public class RoleService : IRoleService
{
private readonly IGenericRepository<Role> _roleRepo;
public RoleService(IGenericRepository<Role> roleRepo)
{
_roleRepo = roleRepo;
}
public async Task<IEnumerable<Role>> GetAllAsync() => await _roleRepo.GetAllAsync();
}
}
Step 3 – Register in Program.cs
📁 Accounting.API/Program.cs
using Accounting.Infrastructure.Repositories.Interfaces;
using Accounting.Infrastructure.Repositories.Implementations;
using Accounting.API.Services.Interfaces;
using Accounting.API.Services.Implementations;
using Accounting.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// PostgreSQL Connection
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));
// Repository pattern
builder.Services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));
builder.Services.AddScoped<IUnitOfWork, UnitOfWork>();
// Services
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IRoleService, RoleService>();
// Swagger + CORS
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddCors(opt =>
{
opt.AddPolicy("AllowAll", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
});
var app = builder.Build();
app.UseCors("AllowAll");
app.UseSwagger();
app.UseSwaggerUI();
app.MapControllers();
app.Run();
Step 4 – Create Controllers
📁 Accounting.API/Controllers/UserController.cs
using Accounting.API.Services.Interfaces;
using Accounting.Core.Entities;
using Microsoft.AspNetCore.Mvc;
namespace Accounting.API.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService) => _userService = userService;
[HttpGet]
public async Task<IActionResult> GetAll() =>
Ok(await _userService.GetAllAsync());
[HttpGet("{id}")]
public async Task<IActionResult> GetById(int id)
{
var user = await _userService.GetByIdAsync(id);
return user == null ? NotFound() : Ok(user);
}
[HttpPost]
public async Task<IActionResult> Create(User user)
{
var created = await _userService.CreateAsync(user);
return CreatedAtAction(nameof(GetById), new { id = created.Id }, created);
}
}
}
📁 Accounting.API/Controllers/RoleController.cs
using Accounting.API.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace Accounting.API.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class RoleController : ControllerBase
{
private readonly IRoleService _roleService;
public RoleController(IRoleService roleService) => _roleService = roleService;
[HttpGet]
public async Task<IActionResult> GetAll() =>
Ok(await _roleService.GetAllAsync());
}
}
Step 5 – Run and Test
Run:
dotnet run
Open browser → https://localhost:5001/swagger
You should see endpoints:
GET /api/users
GET /api/users/{id}
POST /api/users
GET /api/roles
✅ Swagger returns your seeded Admin User and Admin Role.
✅ End of Day 4 Deliverables
| Feature | Status |
|---|---|
| User + Role Services | ✅ |
| User + Role Controllers | ✅ |
| Dependency Injection | ✅ |
| Swagger working | ✅ |
| Database Connected (PostgreSQL) | ✅ |
Next → 📅 Day 5 — Invoice Module (Base Setup)
We’ll add Invoice, InvoiceItem, and Ledger logic with relationships, totals, and repositories.
Would you like me to prepare Day 5 plan (Invoice Module) now?
Top comments (0)