Skip to content

Commit 2277534

Browse files
Login view, controller model, login layout, client side and server side validations added in the web app.
1 parent 4374b9b commit 2277534

File tree

86 files changed

+83220
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+83220
-0
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
</PropertyGroup>
8+
9+
</Project>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
using ApiIntegrationMvc.Areas.Account.Models;
2+
using Microsoft.AspNetCore.Mvc;
3+
4+
namespace ApiIntegrationMvc.Areas.Account.Controllers
5+
{
6+
[Area("Account")]
7+
public class LoginController : Controller
8+
{
9+
[HttpGet]
10+
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
11+
public IActionResult Index()
12+
{
13+
ViewBag.Error = TempData["Error"]; // one-time error
14+
return View(new LoginViewModel()); // empty fields
15+
}
16+
17+
[HttpPost]
18+
[ValidateAntiForgeryToken]
19+
public async Task<IActionResult> Index(LoginViewModel model)
20+
{
21+
if (!ModelState.IsValid)
22+
{
23+
return View(model);
24+
}
25+
26+
if(model.Username == "admin" && model.Password == "123")
27+
return RedirectToAction("Index", "Home"); // PRG on success too
28+
29+
TempData["Error"] = "Invalid username or password.";
30+
return RedirectToAction(nameof(Index)); // ← PRG on failure
31+
32+
}
33+
}
34+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.ComponentModel.DataAnnotations;
2+
3+
namespace ApiIntegrationMvc.Areas.Account.Models
4+
{
5+
public class LoginViewModel
6+
{
7+
[Required(ErrorMessage = "Username is required")]
8+
[StringLength(50)]
9+
public string Username { get; set; }
10+
11+
[Required(ErrorMessage = "Password is required")]
12+
[DataType(DataType.Password)]
13+
[StringLength(100)]
14+
public string Password { get; set; }
15+
}
16+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
@using ApiIntegrationMvc.Areas.Account.Models
2+
@model LoginViewModel
3+
@{
4+
ViewData["Title"] = "Login";
5+
}
6+
7+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" />
8+
<style>
9+
/* Page-specific centering */
10+
.login-container {
11+
height: 100vh;
12+
display: flex;
13+
justify-content: center; /* horizontal */
14+
align-items: center; /* vertical */
15+
16+
}
17+
18+
body {
19+
margin-bottom: 60px;
20+
background: linear-gradient(135deg, #f8f9fa, #e9ecef);
21+
}
22+
23+
.login-card {
24+
width: 100%;
25+
max-width: 400px;
26+
background: #fff;
27+
border-radius: 12px;
28+
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
29+
padding: 2rem;
30+
}
31+
32+
.login-card h2 {
33+
font-weight: 600;
34+
color: #2c3e50;
35+
}
36+
37+
.alert {
38+
border-radius: 8px;
39+
margin-top: 1rem;
40+
}
41+
</style>
42+
43+
<div class="login-container">
44+
<div class="login-card text-center">
45+
<h2 class="mb-4">🔗 Integration Portal</h2>
46+
47+
<form asp-action="Index" asp-controller="Login" method="post" novalidate>
48+
@Html.AntiForgeryToken()
49+
50+
<div asp-validation-summary="ModelOnly" class="alert alert-danger text-start"></div>
51+
52+
<!-- Username with icon -->
53+
<div class="input-group mb-3">
54+
<span class="input-group-text"><i class="bi bi-person"></i></span>
55+
<input asp-for="Username" class="form-control" placeholder="Username" />
56+
</div>
57+
<span asp-validation-for="Username" class="text-danger"></span>
58+
59+
<!-- Password with icon -->
60+
<div class="input-group mb-4">
61+
<span class="input-group-text"><i class="bi bi-lock"></i></span>
62+
<input asp-for="Password" class="form-control" placeholder="Password" />
63+
</div>
64+
<span asp-validation-for="Password" class="text-danger"></span>
65+
66+
<button type="submit" class="btn btn-primary w-100">
67+
<i class="bi bi-box-arrow-in-right"></i> Login
68+
</button>
69+
</form>
70+
71+
@if (ViewBag.Error != null)
72+
{
73+
<div class="alert alert-danger mt-3">@ViewBag.Error</div>
74+
}
75+
</div>
76+
</div>
77+
78+
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
@using ApiIntegrationMvc
2+
@using ApiIntegrationMvc.Models
3+
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
4+
@using ApiIntegrationMvc.Areas.Account.Models
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@{
2+
Layout = "~/Views/Shared/_LoginLayout.cshtml"; // or area-specific layout if you want
3+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using ApiIntegrationMvc.Models;
2+
using Microsoft.AspNetCore.Mvc;
3+
using System.Diagnostics;
4+
5+
namespace ApiIntegrationMvc.Controllers
6+
{
7+
public class HomeController : Controller
8+
{
9+
private readonly ILogger<HomeController> _logger;
10+
11+
public HomeController(ILogger<HomeController> logger)
12+
{
13+
_logger = logger;
14+
}
15+
16+
public IActionResult Index()
17+
{
18+
return View();
19+
}
20+
21+
public IActionResult Privacy()
22+
{
23+
return View();
24+
}
25+
26+
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
27+
public IActionResult Error()
28+
{
29+
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
30+
}
31+
}
32+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace ApiIntegrationMvc.Models
2+
{
3+
public class ErrorViewModel
4+
{
5+
public string? RequestId { get; set; }
6+
7+
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
8+
}
9+
}

ApiIntegrationMvc/Program.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
var builder = WebApplication.CreateBuilder(args);
2+
3+
// Add services to the container.
4+
builder.Services.AddControllersWithViews();
5+
6+
var app = builder.Build();
7+
8+
// Configure the HTTP request pipeline.
9+
if (!app.Environment.IsDevelopment())
10+
{
11+
app.UseExceptionHandler("/Home/Error");
12+
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
13+
app.UseHsts();
14+
}
15+
16+
app.UseHttpsRedirection();
17+
app.UseStaticFiles();
18+
19+
app.UseRouting();
20+
21+
app.UseAuthentication();
22+
app.UseAuthorization();
23+
24+
app.MapControllerRoute(
25+
name: "areas",
26+
pattern: "{area:exists}/{controller=Login}/{action=Index}/{id?}");
27+
28+
app.MapControllerRoute(
29+
name: "root_to_login",
30+
pattern: "",
31+
defaults: new { area = "Account", controller = "Login", action = "Index" });
32+
33+
app.Run();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"$schema": "https://json.schemastore.org/launchsettings.json",
3+
"profiles": {
4+
"http": {
5+
"commandName": "Project",
6+
"dotnetRunMessages": true,
7+
"launchBrowser": true,
8+
"applicationUrl": "http://localhost:5255",
9+
"environmentVariables": {
10+
"ASPNETCORE_ENVIRONMENT": "Development"
11+
}
12+
},
13+
"https": {
14+
"commandName": "Project",
15+
"dotnetRunMessages": true,
16+
"launchBrowser": true,
17+
"applicationUrl": "https://localhost:7078;http://localhost:5255",
18+
"environmentVariables": {
19+
"ASPNETCORE_ENVIRONMENT": "Development"
20+
}
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)