dev-notes/docs/languages/dotnet/asp.net/mvc.md
Marcello Lamonaca 2725e3cb70 feat: restructure docs into "chapters" (#12)
* feat(docker, k8s): create containers folder and kubernetes notes
2023-03-13 12:43:21 +01:00

259 lines
5.8 KiB
Markdown

# ASP.NET (Core) MVC Web App
## Project Structure
```txt
Project
|-Properties
| |- launchSettings.json
|
|-wwwroot --> location of static files
| |-css
| | |- site.css
| |
| |-js
| | |- site.js
| |
| |-lib
| | |- bootstrap
| | |- jquery
| | |- ...
| |
| |- favicon.ico
|
|-Model
| |-ErrorViewModel.cs
| |- Index.cs
| |-...
|
|-Views
| |-Home
| | |- Index.cshtml
| |
| |-Shared
| | |- _Layout.cshtml --> reusable default page layout
| | |- _ValidationScriptsPartial --> jquery validation script imports
| |
| |- _ViewImports.cshtml --> shared imports and tag helpers for all views
| |- _ViewStart.cshtml --> shared values for all views
| |- ...
|
|-Controllers
| |-HomeController.cs
|
|- appsettings.json
|- Program.cs --> App entry-point
|- Startup.cs --> App config
```
**Note**: `_` prefix indicates page to be imported.
## Controllers
```cs
using Microsoft.AspNetCore.Mvc;
using App.Models;
using System.Collections.Generic;
namespace App.Controllers
{
public class CategoryController : Controller
{
private readonly AppDbContext _db;
// get db context through dependency injection
public CategoryController(AppDbContext db)
{
_db = db;
}
// GET /Controller/Index
public IActionResult Index()
{
IEnumerable<Entity> entities = _db.Entities;
return View(Entities); // pass data to the @model
}
// GET /Controller/Create
public IActionResult Create()
{
return View();
}
// POST /Controller/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Entity entity) // receive data from the @model
{
_db.Entities.Add(entity);
_db.SaveChanges();
return RedirectToAction("Index"); // redirection
}
// GET - /Controller/Edit
public IActionResult Edit(int? id)
{
if(id == null || id == 0)
{
return NotFound();
}
Entity entity = _db.Entities.Find(id);
if (entity == null)
{
return NotFound();
}
return View(entity); // return populated form for updating
}
// POST /Controller/Edit
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Entity entity)
{
if (ModelState.IsValid) // all rules in model have been met
{
_db.Entities.Update(entity);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(entity);
}
// GET /controller/Delete
public IActionResult Delete(int? id)
{
if (id == null || id == 0)
{
return NotFound();
}
Entity entity = _db.Entities.Find(id);
if (entity == null)
{
return NotFound();
}
return View(entity); // return populated form for confirmation
}
// POST /Controller/Delete
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Delete(Entity entity)
{
if (ModelState.IsValid) // all rules in model have been met
{
_db.Entities.Remove(entity);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(entity);
}
}
}
```
## Data Validation
### Model Annotations
In `Entity.cs`:
```cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace App.Models
{
public class Entity
{
[DisplayName("Integer Number")]
[Required]
[Range(1, int.MaxValue, ErrorMessage = "Error Message")]
public int IntProp { get; set; }
}
}
```
### Tag Helpers & Client Side Validation
In `View.cshtml`;
```cs
<form method="post" asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group row">
<div class="col-4">
<label asp-for="IntProp"></label>
</div>
<div class="col-8">
<input asp-for="IntProp" class="form-control"/>
<span asp-validation-for="IntProp" class="text-danger"></span> // error message displayed here
</div>
</div>
</form>
// client side validation
@section Scripts{
@{ <partial name="_ValidationScriptsPartial" /> }
}
```
### Server Side Validation
```cs
using Microsoft.AspNetCore.Mvc;
using App.Models;
using System.Collections.Generic;
namespace App.Controllers
{
public class CategoryController : Controller
{
private readonly AppDbContext _db;
// get db context through dependency injection
public CategoryController(AppDbContext db)
{
_db = db;
}
// GET /Controller/Index
public IActionResult Index()
{
IEnumerable<Entity> entities = _db.Entities;
return View(Entities); // pass data to the @model
}
// GET /Controller/Create
public IActionResult Create()
{
return View();
}
// POST /Controller/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Entity entity) // receive data from the @model
{
if (ModelState.IsValid) // all rules in model have been met
{
_db.Entities.Add(entity);
_db.SaveChanges();
return RedirectToAction("Index");
}
return View(entity); // return model and display error messages
}
}
}
```