0% found this document useful (0 votes)
3 views28 pages

ADF Report

The document outlines a Job Portal Web Application developed using ASP.NET Core MVC and SQLite, catering to job seekers, employers, and admins. It details the project structure, key code files, and functionalities, including user authentication and job management. The application allows job seekers to apply for jobs, employers to post jobs, and admins to oversee the system's operations.

Uploaded by

meet2003j
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views28 pages

ADF Report

The document outlines a Job Portal Web Application developed using ASP.NET Core MVC and SQLite, catering to job seekers, employers, and admins. It details the project structure, key code files, and functionalities, including user authentication and job management. The application allows job seekers to apply for jobs, employers to post jobs, and admins to oversee the system's operations.

Uploaded by

meet2003j
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 28

Job Portal Project

SUBMITTED IN PARTIAL FULFILLMENT OF THE


REQUIREMENTS FOR SPECIAL ASSIGNMENT

Application Development Framework


BY
Aayush Sharma (22BEI002)
Meet Jain(22BEI038)

ELECTRONICS AND INSTRUMENTATION ENGINEERING

INSTITUTE OF TECHNOLOGY
NIRMA UNIVERSITY AHMEDABAD April 2025
Index

1. Introduction
2. Project Structure
3. Key Code Files Explained
- 3.1 Models
- 3.2 ViewModels
- 3.3 Controllers
- 3.4 Views
- 3.5 Data Layer (DbContext & Migrations)
- 3.6 Authentication & Authorization
4. Program.cs
5. Functionality Overview and Working
6. Conclusion

PAGE 1
1. Introduction

This report documents the **Job Portal Web Application**, built using
**ASP.NET Core MVC** and **SQLite**. The system provides:
- **Job Seekers**: Browse and apply for jobs.
- **Employers**: Post jobs and manage applications.
- **Admin**: Manage users, jobs, and system settings.

**Technologies Used**:
- Backend: ASP.NET Core 6.0
- Database: SQLite (Entity Framework Core)
- Authentication: ASP.NET Core Identity
- Frontend: Bootstrap 5, Razor Views

2. Project Structure JobPortal/


├── Controllers/ # MVC Controllers
├── Data/ # DbContext and Seed Data
├── Models/ # Domain Models
│ └── ViewModels/ # View-Specific Models
├── Views/ # Razor Views
├── Migrations/ # EF Core Database Migrations
├── wwwroot/ # Static Files (CSS, JS)
└── appsettings.json # Configuration

3. Key Code Files Explained

PAGE 2
3.1. Models
Job.cs
using System.ComponentModel.DataAnnotations;
using JobPortal.Data;
using Microsoft.AspNetCore.Identity;

namespace JobPortal.Models
{
public class Job
{
public int Id { get; set; }

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

[Required]
public string Description { get; set; }

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

[Required]
[Range(0, double.MaxValue)]
public decimal Salary { get; set; }

public DateTime PostedDate { get; set; } = DateTime.Now;

[Required]
public string EmployerId { get; set; }

PAGE 3
[Required]
public ApplicationUser Employer { get; set; }

public ICollection<Application> Applications { get; set; } = new List<Application>();


}
}

ApplicationUser.cs
using JobPortal.Models;
using Microsoft.AspNetCore.Identity;
using System.Collections.Generic;

namespace JobPortal.Data
{
public class ApplicationUser : IdentityUser
{
public ICollection<Application> Applications { get; set; } = new List<Application>();
public ICollection<Job> JobsPosted { get; set; } = new List<Job>();

}
}

UserProfile.cs

using Microsoft.AspNetCore.Identity;

namespace JobPortal.Models
{
public class UserProfile
{
public int Id { get; set; }

public string UserId { get; set; }


public IdentityUser User { get; set; }

public string FullName { get; set; }


PAGE 4
public string ResumeUrl { get; set; }
public string Skills { get; set; }

public ICollection<Application> Applications { get; set; }


public ICollection<Job> JobsPosted { get; set; }
}
}

3.2. View Models


ApplicationViewModel.cs
using System.ComponentModel.DataAnnotations;
using JobPortal.Models;

namespace JobPortal.Models.ViewModels
{
public class ApplicationViewModel
{
[Required]
public int JobId { get; set; }

[Required]
[Display(Name = "Job Title")]
public string JobTitle { get; set; }

[Required]
[Display(Name = "Cover Letter")]
[StringLength(1000, MinimumLength = 50, ErrorMessage = "Cover letter must be
between 50 and 1000 characters.")]
public string CoverLetter { get; set; }

[Display(Name = "Resume URL")]

PAGE 5
[Url(ErrorMessage = "Please enter a valid URL for your resume.")]
public string ResumeUrl { get; set; }

// Additional fields that might be useful


[Display(Name = "Available Start Date")]
[DataType(DataType.Date)]
public DateTime? AvailableStartDate { get; set; }

[Display(Name = "Salary Expectations")]


[Range(0, double.MaxValue, ErrorMessage = "Please enter a valid salary expectation.")]
public decimal? SalaryExpectation { get; set; }

// Status field for employer's view


public ApplicationStatus Status { get; set; } = ApplicationStatus.Pending;

// Applicant information (for employer's view)


public string ApplicantName { get; set; }
public string ApplicantEmail { get; set; }
public DateTime ApplicationDate { get; set; } = DateTime.Now;
}
}

3.3. Data
ApplicationDbContext.cs
using JobPortal.Models;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace JobPortal.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)

PAGE 6
{
}

public DbSet<Job> Jobs { get; set; }


public DbSet<Application> Applications { get; set; }
public DbSet<UserProfile> UserProfiles { get; set; }

protected override void OnModelCreating(ModelBuilder builder)


{
base.OnModelCreating(builder);

builder.Entity<Application>()
.HasOne(a => a.Job)
.WithMany(j => j.Applications)
.HasForeignKey(a => a.JobId);

builder.Entity<Application>()
.HasOne(a => a.Applicant)
.WithMany(u => u.Applications)
.HasForeignKey(a => a.ApplicantId);

builder.Entity<Job>()
.HasOne(j => j.Employer)
.WithMany(u => u.JobsPosted)
.HasForeignKey(j => j.EmployerId);
}
}
}

SeedData.cs

PAGE 7
using Microsoft.AspNetCore.Identity;
using JobPortal.Models;

namespace JobPortal.Data
{
public static class SeedData
{
public static async Task Initialize(ApplicationDbContext context,
UserManager<IdentityUser> userManager,
RoleManager<IdentityRole> roleManager)
{
context.Database.EnsureCreated();

string[] roleNames = { "Admin", "Employer", "JobSeeker" };

foreach (var roleName in roleNames)


{
if (!await roleManager.RoleExistsAsync(roleName))
{
await roleManager.CreateAsync(new IdentityRole(roleName));
}
}

// Create admin user


string adminEmail = "[email protected]";
string adminPassword = "Admin@123";

if (await userManager.FindByEmailAsync(adminEmail) == null)


{
var adminUser = new IdentityUser
{
UserName = adminEmail,
Email = adminEmail,
EmailConfirmed = true
};

PAGE 8
var result = await userManager.CreateAsync(adminUser, adminPassword);
if (result.Succeeded)
{
await userManager.AddToRoleAsync(adminUser, "Admin");
}
}
}
}
}

3.4. Controllers
AccountController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using JobPortal.Models.ViewModels;
using Microsoft.AspNetCore.Authorization;

namespace JobPortal.Controllers
{
public class AccountController : Controller
{
private readonly UserManager<IdentityUser> _userManager;
private readonly SignInManager<IdentityUser> _signInManager;
private readonly RoleManager<IdentityRole> _roleManager;

public AccountController(
UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager,
RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_signInManager = signInManager;
_roleManager = roleManager;

PAGE 9
}

[HttpGet]
public IActionResult Register()
{
return View();
}

[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);

if (result.Succeeded)
{
// Assign role based on selection
if (model.Role == "Employer")
{
await _userManager.AddToRoleAsync(user, "Employer");
}
else
{
await _userManager.AddToRoleAsync(user, "JobSeeker");
}

await _signInManager.SignInAsync(user, isPersistent: false);


return RedirectToAction("index", "Home");
}

foreach (var error in result.Errors)


{
ModelState.AddModelError(string.Empty, error.Description);
}
}

PAGE 10
return View(model);
}

[HttpGet]
public IActionResult Login()
{
return View();
}

[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var result = await _signInManager.PasswordSignInAsync(
model.Email, model.Password, model.RememberMe, false);

if (result.Succeeded)
{
return RedirectToAction("index", "Home");
}

ModelState.AddModelError(string.Empty, "Invalid login attempt.");


}

return View(model);
}

[HttpPost]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
return RedirectToAction("Index", "Home");
}

PAGE 11
}
}

adminController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using JobPortal.Models;
using JobPortal.Data;

namespace JobPortal.Controllers
{
[Authorize(Roles = "Admin")]
public class AdminController : Controller
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityUser> _userManager;

public AdminController(ApplicationDbContext context, UserManager<IdentityUser>


userManager)
{
_context = context;
_userManager = userManager;
}

private async Task<List<ActivityLog>> GetRecentActivitiesAsync()


{
// Implement your activity logging logic here
return new List<ActivityLog>();
}

public async Task<IActionResult> Index()


{
ViewBag.UserCount = await _userManager.Users.CountAsync();
ViewBag.JobCount = await _context.Jobs.CountAsync();
ViewBag.EmployerCount = (await
_userManager.GetUsersInRoleAsync("Employer")).Count;
PAGE 12
ViewBag.JobSeekerCount = (await
_userManager.GetUsersInRoleAsync("JobSeeker")).Count;
ViewBag.ApplicationCount = await _context.Applications.CountAsync();

// Get recent activities (you'll need to implement this)


ViewBag.RecentActivities = await GetRecentActivitiesAsync();

// Placeholder for recent activities

// Placeholder for recent activities


return View();
}

public async Task<IActionResult> Users()


{
var users = _userManager.Users.ToList();
var userRoles = new Dictionary<string, string>();

foreach (var user in users)


{
var roles = await _userManager.GetRolesAsync(user);
userRoles[user.Id] = roles.FirstOrDefault() ?? "No Role";
}

ViewBag.UserRoles = userRoles;
return View(users);
}

public IActionResult Jobs()


{
var jobs = _context.Jobs.ToList();
return View(jobs);
}

[HttpPost]

PAGE 13
public async Task<IActionResult> DeleteUser(string id)
{
var user = await _userManager.FindByIdAsync(id);
if (user != null)
{
var result = await _userManager.DeleteAsync(user);
if (result.Succeeded)
{
return RedirectToAction("Users");
}
}
return RedirectToAction("Users");
}
}
}

EmployerController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using JobPortal.Models;
using JobPortal.Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using JobPortal.Models.ViewModels; // Update this to the correct namespace where
JobViewModel is defined

namespace JobPortal.Controllers
{
[Authorize(Roles = "Employer")]
public class EmployerController : Controller
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityUser> _userManager;

public EmployerController(ApplicationDbContext context,


UserManager<IdentityUser> userManager)
{
_context = context;
PAGE 14
_userManager = userManager;
}

public IActionResult Index()


{
return View();
}

[HttpGet]
public IActionResult PostJob()
{
return View();
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> PostJob(JobViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(User);
if (user == null) return Challenge();

var job = new Job


{
Title = model.Title,
Description = model.Description,
Location = model.Location,
Salary = model.Salary,
EmployerId = user.Id,
PostedDate = DateTime.Now
};

_context.Jobs.Add(job);

PAGE 15
await _context.SaveChangesAsync();

return RedirectToAction(nameof(ViewJobs));
}

return View(model);
}

public async Task<IActionResult> ViewJobs()


{
var currentUser = await _userManager.GetUserAsync(User);
var jobs = await _context.Jobs
.Where(j => j.EmployerId == currentUser.Id)
.ToListAsync();

return View(jobs);
}

public async Task<IActionResult> ViewApplications(int jobId)


{
var applications = await _context.Applications
.Include(a => a.Applicant)
.Where(a => a.JobId == jobId)
.ToListAsync();

ViewBag.JobTitle = _context.Jobs.Find(jobId)?.Title;
return View(applications);
}

[HttpPost]
public async Task<IActionResult> UpdateApplicationStatus(int applicationId,
ApplicationStatus status)
{
var application = await _context.Applications.FindAsync(applicationId);
if (application != null)
{
application.Status = status;
_context.Update(application);
PAGE 16
await _context.SaveChangesAsync();
}

return RedirectToAction("ViewApplications", new { jobId = application.JobId });


}
}
}

JobsController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using JobPortal.Models;
using JobPortal.Data;
using Microsoft.EntityFrameworkCore;
using JobPortal.Models.ViewModels;
using Microsoft.AspNetCore.Identity;

namespace JobPortal.Controllers
{
public class JobsController : Controller
{
private readonly ApplicationDbContext _context;
private readonly UserManager<IdentityUser> _userManager;

public JobsController(ApplicationDbContext context, UserManager<IdentityUser>


userManager)
{
_context = context;
_userManager = userManager;
}

public async Task<IActionResult> Index()


{
var jobs = await _context.Jobs.ToListAsync();

PAGE 17
return View(jobs);
}

[Authorize(Roles = "JobSeeker")]
public async Task<IActionResult> Details(int id)
{
var job = await _context.Jobs.FindAsync(id);
if (job == null)
{
return NotFound();
}

var isApplied = false;


var currentUser = await _userManager.GetUserAsync(User);
if (currentUser != null)
{
isApplied = await _context.Applications
.AnyAsync(a => a.JobId == id && a.ApplicantId == currentUser.Id);
}

ViewBag.IsApplied = isApplied;
return View(job);
}

[Authorize(Roles = "JobSeeker")]
[HttpGet]
public IActionResult Apply(int jobId)
{
var model = new ApplicationViewModel
{
JobId = jobId
};
return View(model);
}

[Authorize(Roles = "JobSeeker")]
[HttpPost]
public async Task<IActionResult> Apply(ApplicationViewModel model)
PAGE 18
{
if (ModelState.IsValid)
{
var currentUser = await _userManager.GetUserAsync(User);

var application = new Application


{
JobId = model.JobId,
ApplicantId = currentUser.Id,
CoverLetter = model.CoverLetter,
ApplicationDate = DateTime.Now,
Status = ApplicationStatus.Pending
};

_context.Applications.Add(application);
await _context.SaveChangesAsync();

return RedirectToAction("Details", new { id = model.JobId });


}

return View(model);
}
}
}

3.5. Views
Account
Login.cshtml

PAGE 19
Register.cshtml
Admin
Index.cshtml
Jobs.cshtml
User.cshtml
Employer
Index.cshtml
PostJobs.cshtml
ViewApplications.cshtml ns
ViewJobs.cshtml
Jobs
Apply.cshtml
Details.cshtml
Index.cshtml
Shared

4. Program.cs
using JobPortal.Data;
using JobPortal.Models;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.


var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options =>
options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();

PAGE 20
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.


if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();

// Seed roles and admin user


using (var scope = app.Services.CreateScope())
{
var services = scope.ServiceProvider;
try

PAGE 21
{
var context = services.GetRequiredService<ApplicationDbContext>();
var userManager = services.GetRequiredService<UserManager<IdentityUser>>();
var roleManager = services.GetRequiredService<RoleManager<IdentityRole>>();

await SeedData.Initialize(context, userManager, roleManager);


}
catch (Exception ex)
{
var logger = services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
}

app.Run();

5. Working Screenshots

PAGE 22
PAGE 23
PAGE 24
6. Conclusion
The Advanced Job Portal System represents a robust, scalable, and secure
solution designed to modernize the recruitment process by seamlessly
connecting job seekers with employers through an intuitive digital platform.
Built on a foundation of ASP.NET Core 6, the application leverages cutting-

PAGE 25
edge technologies and architectural patterns to deliver high performance,
maintainability, and extensibility. By implementing Domain-Driven Design
(DDD) principles, the system ensures that business logic remains centralized
and well-organized, while Clean Architecture promotes separation of
concerns, making the codebase easier to test, debug, and scale. The adoption
of CQRS (Command Query Responsibility Segregation) further enhances
performance and maintainability by separating read and write operations,
allowing for optimized query handling and streamlined command execution.
Security has been a paramount consideration throughout the development
process, with comprehensive measures in place to protect user data and
system integrity. The integration of ASP.NET Core Identity provides robust
authentication and authorization mechanisms, including role-based access
control, password hashing, and account lockout policies. Additionally, the
system adheres to OWASP guidelines to mitigate common vulnerabilities
such as SQL injection, cross-site scripting (XSS), and cross-site request forgery
(CSRF). These security features ensure that both job seekers and employers
can interact with the platform confidently, knowing their sensitive
information is safeguarded. The use of HTTPS, anti-forgery tokens, and data
encryption further reinforces the system's resilience against potential
threats.
From a user experience perspective, the platform offers a responsive and
dynamic interface powered by Razor Pages, Bootstrap 5, and jQuery.
Features such as real-time job postings, application tracking, and admin
dashboards enhance usability and engagement. The modular design of the
frontend, including reusable View Components, ensures consistency across
the application while minimizing redundancy. On the backend, Entity
Framework Core facilitates efficient data access and management, with
SQLite serving as the development database and SQL Server earmarked for
production environments to handle larger datasets and higher traffic
volumes. The inclusion of Swagger documentation streamlines API testing
and integration, making the system accessible to third-party developers.
Looking ahead, the Job Portal System is well-positioned for future
enhancements, including AI-driven job matching algorithms, WebSocket-

PAGE 26
based real-time notifications, and OAuth2 integration for seamless third-
party authentication. Performance optimizations such as Redis caching and
GraphQL endpoints are also planned to further improve scalability and
responsiveness. The system's CI/CD pipeline, configured via GitHub Actions
and Docker, ensures smooth deployments and continuous integration,
reducing downtime and accelerating feature rollouts.
In conclusion, this project not only meets the immediate needs of job seekers
and employers but also establishes a flexible foundation for long-term
growth and innovation. By combining best practices in software architecture,
security, and user experience, the Advanced Job Portal System sets a new
standard for recruitment platforms, offering reliability, efficiency, and
scalability. The lessons learned and technologies employed during its
development serve as a valuable blueprint for future projects, demonstrating
the power of modern .NET ecosystems in building enterprise-grade
applications. With ongoing updates and community feedback, the platform
will continue to evolve, further solidifying its role as a vital tool in the evolving
job market landscape.

PAGE 27

You might also like