Skip to main content

Complete SMS API Implementation

Level: Advanced

ℹ️ What You'll Learn
  • Complete SMS API structure: Controllers → Services → Repositories → DbContext → Database
  • Controller layer: StudentsController, TeachersController, ExamsController, FeesController, AuthController
  • Service layer: BusinessLogic (validation, calculations), calls Repository for data access
  • Repository layer: Data access abstractions (IStudentRepository, ITeacherRepository)
  • DbContext: EF Core bridge to database (Student, Teacher, Exam, Fee, FeePayment entities)
  • Authentication controller: POST /auth/login validates credentials, returns JWT token
  • Students endpoints: CRUD operations (list, detail, create, update, delete) with authorization checks
  • Teachers endpoints: Similar CRUD for teachers (with authorization to restrict access to own class)
  • Exams endpoints: Get all exams, create exam, retrieve exam results by exam ID
  • Fees endpoints: Get student fee account, record fee payment with authorization checks
  • Error handling: Each endpoint returns appropriate status (200, 201, 400, 401, 403, 404, 500)
  • Database transaction handling: Multiple operations (create student + create default fee account) in single transaction
  • Logging: Log important actions (student created, fee payment, authentication failure)
  • Testing: Manual with Postman/Swagger, unit tests for services, integration tests for endpoints
  • Deployment: Deploy to Azure App Service, configure production database, enable HTTPS

Project Structure

SMS.Api/
├── Controllers/
│ ├── AuthController.cs
│ ├── StudentsController.cs
│ ├── ExamsController.cs
│ └── FeesController.cs
├── Services/
│ ├── IStudentService.cs
│ ├── StudentService.cs
│ ├── IExamService.cs
│ └── ExamService.cs
├── Models/
│ ├── Student.cs
│ ├── Exam.cs
│ └── LoginRequest.cs
├── Middleware/
│ └── ExceptionHandlingMiddleware.cs
├── Program.cs
├── appsettings.json
└── appsettings.Production.json

Program.cs Configuration

var builder = WebApplicationBuilder.CreateBuilder(args);

// Add services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

// Database
builder.Services.AddScoped<SmsDbContext>();

// Services
builder.Services.AddScoped<IStudentService, StudentService>();
builder.Services.AddScoped<IExamService, ExamService>();
builder.Services.AddScoped<IFeeService, FeeService>();

// Authentication
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => { /* config */ });

// CORS
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowReact", builder =>
{
builder.WithOrigins("http://localhost:3000")
.AllowAnyMethod()
.AllowAnyHeader();
});
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseCors("AllowReact");
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

app.Run();

Student Service Implementation

public interface IStudentService
{
Task<List<Student>> GetStudentsAsync(int? classNumber = null);
Task<Student> GetStudentAsync(int id);
Task<Student> CreateStudentAsync(Student student);
Task UpdateStudentAsync(int id, Student student);
Task DeleteStudentAsync(int id);
}

public class StudentService : IStudentService
{
private readonly SmsDbContext _context;
private readonly ILogger<StudentService> _logger;

public StudentService(SmsDbContext context, ILogger<StudentService> logger)
{
_context = context;
_logger = logger;
}

public async Task<List<Student>> GetStudentsAsync(int? classNumber = null)
{
_logger.LogInformation("Getting students. Filter: {Filter}", classNumber);

var query = _context.Students.AsQueryable();
if (classNumber.HasValue)
query = query.Where(s => s.ClassNumber == classNumber.Value);

return await query.ToListAsync();
}

public async Task<Student> GetStudentAsync(int id)
{
var student = await _context.Students.FindAsync(id);
if (student == null)
throw new StudentNotFoundException(id);

return student;
}

public async Task<Student> CreateStudentAsync(Student student)
{
if (await _context.Students.AnyAsync(s => s.RollNumber == student.RollNumber))
throw new DuplicateRollNumberException(student.RollNumber);

_context.Students.Add(student);
await _context.SaveChangesAsync();

_logger.LogInformation("Student created: {Id}", student.Id);
return student;
}

public async Task UpdateStudentAsync(int id, Student student)
{
var existing = await GetStudentAsync(id);

existing.Name = student.Name;
existing.ClassNumber = student.ClassNumber;
existing.Status = student.Status;

await _context.SaveChangesAsync();
_logger.LogInformation("Student updated: {Id}", id);
}

public async Task DeleteStudentAsync(int id)
{
var student = await GetStudentAsync(id);
_context.Students.Remove(student);
await _context.SaveChangesAsync();

_logger.LogInformation("Student deleted: {Id}", id);
}
}

Student Controller

[ApiController]
[Route("api/[controller]")]
public class StudentsController : ControllerBase
{
private readonly IStudentService _service;
private readonly ILogger<StudentsController> _logger;

public StudentsController(IStudentService service, ILogger<StudentsController> logger)
{
_service = service;
_logger = logger;
}

[HttpGet]
public async Task<ActionResult<List<Student>>> GetStudents([FromQuery] int? classNumber)
{
var students = await _service.GetStudentsAsync(classNumber);
return Ok(students);
}

[Authorize]
[HttpGet("{id}")]
public async Task<ActionResult<Student>> GetStudent(int id)
{
try
{
var student = await _service.GetStudentAsync(id);
return Ok(student);
}
catch (StudentNotFoundException ex)
{
return NotFound(new { error = ex.Message });
}
}

[Authorize(Roles = "Admin")]
[HttpPost]
public async Task<ActionResult<Student>> CreateStudent([FromBody] Student student)
{
try
{
var result = await _service.CreateStudentAsync(student);
return CreatedAtAction(nameof(GetStudent), new { id = result.Id }, result);
}
catch (DuplicateRollNumberException ex)
{
return Conflict(new { error = ex.Message });
}
}

[Authorize(Roles = "Admin")]
[HttpPut("{id}")]
public async Task<ActionResult> UpdateStudent(int id, [FromBody] Student student)
{
try
{
await _service.UpdateStudentAsync(id, student);
return NoContent();
}
catch (StudentNotFoundException ex)
{
return NotFound(new { error = ex.Message });
}
}

[Authorize(Roles = "Admin")]
[HttpDelete("{id}")]
public async Task<ActionResult> DeleteStudent(int id)
{
try
{
await _service.DeleteStudentAsync(id);
return NoContent();
}
catch (StudentNotFoundException ex)
{
return NotFound(new { error = ex.Message });
}
}
}

Data Model

public class Student
{
[Key]
public int Id { get; set; }

[Required]
[StringLength(100)]
public string Name { get; set; }

[Required]
[StringLength(50)]
public string RollNumber { get; set; }

[Required]
[Range(1, 12)]
public int ClassNumber { get; set; }

[Required]
public StudentStatus Status { get; set; }

public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

public enum StudentStatus { Active, Inactive, Graduated }

API Endpoints Summary

GET /api/students List all students
GET /api/students/{id} Get student details
POST /api/students Create student
PUT /api/students/{id} Update student
DELETE /api/students/{id} Delete student
GET /api/exams List exams
POST /api/exams Create exam
GET /api/fees/{studentId} Get student fees
POST /api/fees/{studentId}/payments Record payment

Key Takeaways

  • Layered architecture = separation
  • DI = loose coupling
  • Async = scalable
  • Error handling = robustness
  • Testing = confidence
💡 API Design Tip

Consistent structure across all endpoints. Easy to extend later.

🤖Use AI to Learn Faster

Use ChatGPT, Claude, or Copilot to go deeper on Complete SMS API. Try these prompts:

  • "How do I structure a large API project?"
  • "Why use service layer pattern?"
  • "What's the best way to handle errors?"
  • "Quiz me on API design"

💡 Tip: After reading this article, paste your own code into AI and ask "What could go wrong here and why?" — fastest way to find edge cases and deepen understanding.


Use these links to complete the full Final Project topic from the top menu:

Target search terms for this lesson: school management system api asp.net core, asp.net core web api project with sql server, asp.net core web api crud project, entity framework core project example, dotnet project for resume.


Use these links to continue the full Backend > ASP.NET Core Web API topic from the top menu:

Target search terms for this lesson: asp.net core web api with sql server, asp.net core web api crud, asp.net core web api with entity framework core, school management system api asp.net core.


nexcoding.in