MVC Notes: Ahmed Zaher
MVC Notes: Ahmed Zaher
NET
MVC NOTES
Ahmed Zaher
ASP.NET MVC Notes
Day 1: Routing & Action Results
1. Routing and Endpoints
/Emp/<ClassName>/Index<FunctionName>
Note :
IAc tion R esult is an interface in ASP.NET Core MVC that represents the result of an action method in a controller. It allows you
to return different types of responses, such as views, JSON data, HTTP status codes, or redirections.
}
<!- - I n l i n e Statment-- >
<h2>@x</h2>
@y
<!- - Condition statment-- >
@ if ( x > y){
Ahmed Zaher
Day 2: Data Passing Methods
1. Passing Data from Action to View
@model takes one data type, but we have three methods to pass multiple data types:
1. ViewData
ViewBag.Property = dynamicValue;
At Controller
At View:
@model Employee
@{
ViewData [ " Title " ] = " I T I Details " ;
}
<h2 style="color:@ViewBag.Color">@Model.Name</h2>
<h1>@ViewData["Msg"]</h1>
<h2>@(int.Parse(ViewData["Temp"].ToString())-10)</h2>
StateManagement
2. Data Persistence (Session, TempData, Cookies)
When a request is made, the controller object is created and destroyed after execution.
To persist data across requests or getting some data from the Object , use:
Ahmed Zaher
Feature TempData Session Cookies
Lifetime Expires after one request (unless Expires when session ends Expires based on Expires
Keep() is used) ( IdleTimeout ) property
Persistence Survives redirects but not full refreshes Survives full refresh, redirects, Survives browser restarts (if
and navigation not expired)
Use Case Passing temporary data between two Storing user-specific data during Storing small, persistent
actions a session user preferences
1. TempData
2. Session
1. Session Creation:
When a user first sends a request to the server (e.g., by visiting a website), the server creates a session for that user.
The server generates a unique session ID, typically a random string or number.
This Session ID is stored in a Cookie on the user's browser , but the actual data stored in Server
At Main Function :
// or
builder . Services . AddSession (); / / Default Time i s 20 min
so ,
app.UseRouting ();
app.MapControllerRoute(
name: " default " ,
p a ttern : "{controller=Home}/{action=Index}/{id?}");
// app . Map ("/ djhsdjh ", (app) => { });
#endregion
app.Run();
}
3. Cookies
Ahmed Zaher
The session ID stored in the cookie is only used by the browser to identify the session
it doesn’t store user data (just the ID).
Cookie Data is stored on the client’s browser.
Cookies are sent back to the server automatically with each request, allowing the server to retrieve session-specific data (like
user authentication, preferences, etc.).
Can set expiration time.
Cookies Are Added in Response
Request is used for Read Only
Ahmed Zaher
Day 3: Model Binding
Bind/ClassName/FunctionName?name=ahmed&age=20
Request . QueryString
Important Notes
✅ Extra parameters will be ignored if not required by the function.
✅ Missing parameters will take default values:
int → 0
s t r ing → null
Ahmed Zaher
/Bind/ClassName/FunctionName?name=ahmed&age=20
/Bind/ → Segment
/ClassName/ → Segment
/FunctionName?name=ahmed&age=20 → Query String Parameters
Bind/ClassName/FunctionName?id=10
Bind/ClassName/FunctionName/10
Request.RouteValues
RouteValues take priority over query string parameters. If both are present, ASP.NET will use RouteValues.
/Binding/Emp?id=1&name=ahmed&salary=1000
or /Binding/Emp/1?&name=ahmed&salary=1000 / / i d i s added as a segment
Ahmed Zaher
This will automatically map to an Employee ( Emp ) object with properties I d , Name , and Salary .
Request.Form
Day 4
HTML Helper in ASP.NET MVC
Example:
Ahmed Zaher
1- HTML Helper (Pure C#)
What are HTML Helpers?
HTML Helpers are utility methods in ASP.NET MVC that generate HTML elements dynamically inside a View instead of
writing static HTML manually.
Generates:
< input type = " text " name="Username" value="JohnDoe" class = " form - control " / >
@using (Html.BeginForm())
{
< div class = " form - group">
@Html.LaberFor(b=>b.name);
/ / w i l l make the label name for the attribute i n the c l a s s but
/ / i f i t found [ Display (name="Name")] w i l l put i t to the label
@Html.TextBoxFor(m => m.Name, new { @class = "form-control " , placeholder = " Enter your name" })
</ div >
@ if (ViewBag.Message != null )
{
Ahmed Zaher
<p>@ViewBag.Message</p>
}
Explanation
Html.TextBoxFor(m => m.Name) binds directly to the Name property in UserModel .
The model ensures type safety and allows data validation.
When the form is submitted, the controller receives the model with user input.
If valid, the name is displayed in ViewBag.Message .
Html.EditorFor() Examples
@using (Html.BeginForm())
{
< div class = " form - group">
<label>Name:</label> Ahmed Zaher
@Html.EditorFor(m => m.Name, new { htmlAttributes = new { @class = "form-control " , placeholder =
" Enter name" } })
</ div >
[DataType(DataType.Password)]
[ Display ( Password = " User Password")]
public s t ring Password { get ; set ; }
}
@using (Html.BeginForm())
{
< div class = " form - group"> Ahmed Zaher
< label > Password :</ label >
@Html.EditorFor(m => m.Password, new { htmlAttributes = new { @class = "form-control " , placeholder =
" Enter password" } })
</ div >
✅ Key Differences:
EditorFor() automatically detects the input type based on the model's data annotation! 🚀
V2 - Tag Helper
Full Tag Helper Example in ASP.NET Core
@model UserModel
<button type = " submit " class = " btn btn - primary">Submit</button>
</form>
@section S c ript s {
< partial name = " _ ValidationScriptsPartial " / >
}
@model EmpWithDEptListViewModel
@{
ViewData [ " Title " ] = " Edit " ;
SelectList s elec t L is t s = new SelectList ( Model . DeptList , " Field _ Value " , " Field _ Name " ); /* to make casting
to IEnumerable */
}
<h1>Edit</h1>
Ahmed Zaher
<form method="post" asp - action = " SAveEdit >
< div >
< input asp - for = " StId " type="hidden" />
< label asp - for="DepartmentID"></label>
@* < input type="number" value="@Model.DepartmentID" id="DepartmentID" name="DepartmentID"
class = " form form-control " /> *@
< select asp - for="DepartmentID" asp - items = " selectLists " ></ select >
</ div >
< input type="submit" value="Save" class = " btn btn-success " />
</form>
By default, when using <form asp-action="SomeAction"> , the method is POST, unless specified otherwise.
Feature Usage
<form> (No asp-c ontroller or asp-action ) Since it's in the same view, method="post" is enough
asp-for on <input> & < l ab el > Automatically binds fields to the model
asp-v a lid a tion - for Displays validation messages dynamically
@section Sc ripts Ensures client-side validation works
Tag Helpers make Razor views more HTML-friendly, reducing the need for HtmlHelpers .
When using Tag Helpers for a form's submit button, you explicitly set the ty pe="submit" attribute to ensure it functions correctly.
Note :
Ahmed Zaher
asp-for="X" does... Result in HTML
Sets name name="X"
Sets id id=" X"
Sets value value="Model.X"
Works with validation <span asp-validation - for = " X " > ... < / span >
_Layout.cshtml
Views/Shared/_Layout.cshtml
Ahmed Zaher
You can have multiple layout styles and apply them selectively.
@model EmpWithDeptListViewModel
@{
ViewData [ " Title " ] = " Edit " ;
Layout = "NewLayout"; / / You can set i t to null to remove layout
}
RenderBody vs RenderSection
Example in _Layout.cshtml :
<!DOCTYPE html>
<html>
<head>
< title > @ ViewData [" Title "] < / title >
</head> Ahmed Zaher
<body>
<header>My Header</header>
< div >
@RenderBody() < !- - The view w i l l be injected here - - >
< / div >
<footer>My Footer < / footer >
</body>
</html>
Example in _Layout.cshtml :
<!DOCTYPE html>
<html>
<head>
< title > @ ViewData [" Title "] < / title >
</head>
<body>
<header>My Header</header>
Inside View.cshtml
@section Sidebar {
< p > This i s the Sidebar content</p>
}
Summary
Feature Purpose
@RenderBody Inserts the main view content inside the layout.
@RenderSection Allows custom sections to be injected into the layout.
Layout = "NewLayout" Changes the default layout for a specific view.
Ahmed Zaher
DAY 5
Validation
[ValidateAntiForgeryToken] in ASP.NET MVC & Core
What is [ValidateAntiForgeryToken] ?
[ ValidateAntiForgeryToken ] is an attribute used in ASP.NET MVC & ASP.NET Core to prevent Cross-Site Request Forgery
(CSRF) attacks by ensuring that form submissions are legitimate and come from the same site.
Why is it Important?
Without CSRF protection, an attacker could trick a logged-in user into unknowingly submitting a form that performs malicious
actions, such as:
Transferring money
Changing an account password
Deleting a user account
This attribute ensures that every POST request contains a valid anti-forgery token, making it harder for attackers to forge
requests.
[ HttpPost ]
[ ValidateAntiForgeryToken ]
public IActionResult SubmitForm(UserModel model)
{
i f ( ModelState . IsValid )
{
/ / Process form submission
return RedirectToAction ( " Success " );
}
return View(model);
}
Ahmed Zaher
🔹 Using HtmlHelpers (ASP.NET MVC & Core)
✔ If you're using Html.BeginForm() , you must manually add
@Html.AntiForgeryToken().
@using (Html.BeginForm("SubmitForm", "Home", FormMethod.Post))
{
@Html.AntiForgeryToken();
< label > Email :</ label >
@Html.TextBoxFor(model => model.Email, new { @class = "form-control " }) < button type = "submit" >
Submit </ button >
}
✔ Without @Html.AntiForgeryToken() , the request will fail with HTTP 403 Forbidden.
Ahmed Zaher
Scenario Should You Use [ValidateAntiForgeryToken] ?
POST request (modifies data) ✅ Yes
GET request (just displays data) ❌ No
Login, Register, Delete, Update actions ✅ Yes
API request (without authentication) ❌ No (Use JWT or OAuth)
Summary
Feature [ValidateAntiForgeryToken]
Example Code
🔹 Controller
Ahmed Zaher
Final Notes
Tag Helpers in ASP.NET Core automatically include the anti-forgery token.
HtmlHelpers in ASP.NET MVC/Core require @Html.AntiForgeryToken() manually.
If you forget to add the anti-forgery token, the request will be rejected (403 Forbidden).
Note :
in ASP.NET MVC/Core, you cannot override an action method unless they have different HTTP verbs (e.g., GET and POST ) or
different method signatures (e.g., different parameters).
✅ Correct Approach:
Use attribute routing ( [HttpGet] , [ HttpPost ] , etc.) to differentiate actions.
using System.ComponentModel.DataAnnotations;
At Controller
[ HttpPost ]
public IActionResult Register(UserViewModel model)
{
//ModelState i s Dictionary
/ / i t ' s key i s Property name and i t ' s value i s property value
i f (! ModelState . IsValid )
Ahmed Zaher
{
return View(model); / / Return the view with validation errors
}
ModelState is Dictionary
it's key is Property name and it's value is property value
At View
Ahmed Zaher
<button type = " submit " class = " btn btn - primary " > Register < / button >
</form>
<div asp-v a lid a tion - summary="All" c l a ss = " text - danger"></div> : Displays and gather all validation errors at the top of
the form.
The " All " option shows both model-level and property-level errors :
1 Model-level errors (e.g., errors added manually in the controller using- ModelState.AddModelError("", "message") )
2 Field-specific errors (e.g., [Required] , [EmailAddress] )
You can change it to: "ModelOnly" → Displays only model-level validation errors.
"None" → Hides the validation summary (not recommended unless you use inline messages only).
i f ( std . DeptId == 0)
{
ModelState.AddModelError("DeptId", " Select Department " );
return View("View1", std );
}
Ahmed Zaher
Note That It is Server-Side
If I want to create a unique attribute for a name, I need to create a new model (class) and name it with 'Attribute' at the end, like
UniqueAttribute .
i f ( student != null )
{
return new ValidationResult ( " Error Message");
}
// At the Model
[Unique(msg ="Any Message")]
public s t ring StFname { get ; set ; }
Ahmed Zaher
1. object? value
This is the value of the property that the attribute is applied to.
It contains the data that needs to be validated.
It can be null , so you must check before using it.
You typically cast it to the expected type ( s t ring , i n t , etc.).
Note Again :
it is Server Side
To enable custom client-side validation, we need to use jQuery along with jQuery Va lid a tion and jQuery Unobtrusive
Va lid a tion .
You need to include the required JavaScript libraries at the end of the view:
< script src = " ~ / lib / jquery / dist / jquery . min . js " ></ script >
< script src = " ~ / lib / jquery - validation / dist / jquery . validate . min . js " ></ script > < script src = " ~ / lib / jquery -
Ahmed Zaher
validation - unobtrusive / jquery . validate . unobtrusive . min . js " ></ script >
Instead of adding scripts manually in every view, it's best to load them in the _Layout.cshtml file using the built-in
@RenderSectionAsync("Scripts") method.
This allows each view to inject its own scripts inside a S c ript s section without duplicating code.
@section S c ript s {
< script src = " ~ / lib / jquery - validation / dist / jquery . validate . min . js " >< / script >
< script src = " ~ / lib / jquery - validation - unobtrusive / jquery . validate . unobtrusive . min . js " >< / script >
}
at model
public c l as s UserModel
{
[Required]
[ Remote ( action :" check ", controller :" Instructor ", ErrorMessage ="MSG")]
public s t ring Username { get ; set ; }
}
at controlled
public c l as s UserModel
{
Ahmed Zaher
[Required]
[ Remote ( action :" check ", controller :" Instructor ", ErrorMessage ="MSG"
, AdditionalFields =" Address , Email"
)]
public s t ring Username { get ; set ; }
public s t ring Email { get ; set ; }
public s t ring Address { get ; set ; }
}
At Controller
Day 6
1 MiddleWare
MiddleWares are Methods in Web Application
in .NET Core, when a request arrives at IIS, it forwards the request to the ASP.NET Core runtime Proxy (specifically Kestrel).
Kestrel then executes the middleware pipeline configured in the application.
Middleware in ASP.NET Core is a component that is part of the request processing pipeline. It handles:
1 Incoming requests (before they reach your controller and after the session being created )
Note that :
We can build our own middleware by providing a delegate, and there are three types of middleware:
1. Execute then invoke the next component ⇒ Use
2. Execute and terminate the pipeline ⇒ Run
3. Branch based on URL and execute a delegate, .Map(url , Exec) ⇒ Map
Example :-
Ahmed Zaher
public s t ati c void Main ( string [] args )
{
var builder = WebApplication . CreateBuilder ( args );
//
});
app.Use(async ( httpContext , Next) =>
{
await httpContext.Response .WriteAsync ("2 )Middleware 2\n");
await Next . Invoke ();
await httpContext.Response.WriteAsync("2)Middleware 2-----\ n " );
});
app.Run(async ( httpContext ) =>
{
await httpContext.Response.WriteAsync("3)Terminate\n");
Ahmed Zaher
});
app.Use(async ( httpContext , Next) =>
{
await httpContext.Response .WriteAsync ("4 )Middleware 4\n");
await Next . Invoke ();
//
});
app.Run();
}
Output :
1) Middleware 1
2) Middleware 2
3)Terminate
2)Middleware 2-- - - -
3) Middleware 1--
Bulit in MiddleWare
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
app . UseStaticFiles (); / / for jquery and bootstrap
app.MapControllerRoute(
name: " default " ,
p a ttern : "{controller=Home}/{action=Index}/{id?}");
#endregion
app.Run();
}
Note :
if (!app.Environment.IsDevelopment())
{
Ahmed Zaher
app.UseExceptionHandler("/Home/Error");
}
it used For end-user not Developer that make it easy for him to explore Errors and exceptions
2- StateManagment
Explained At Day 2 (Page 6 )
Ahmed Zaher
Day 7
the best practice in software architecture (especially in C# and ASP.NET environments) is to follow this flow:
Note:
A Repository is a class (or interface + class) that:
Encapsulates the logic required to access data sources (e.g., SQL Server, MongoDB, APIs).
Provides CRUD (Create , Read , Update , Delete ) operations for a specific model.
Hides all the low-level database details from the rest of the app
this approach is called Repository Pattern we try not to write code at controller
So :
Controller interacts with the Repository, and the Repository interacts with the Database Context (often referred to as the
DbContext in Entity Framework for C#).
SOLID Principles in C#
1. Single Responsibility Principle (SRP)
What It Means:
A class should have only one reason to change.
Each class should focus on a single task/responsibility, which improves maintainability, testability, and readability.
Ahmed Zaher
❌ Violates SRP
}
}
✅ Applies SRP
❌ Violates OCP
/ / CreditCard logic
/ / PayPal logic
} Ahmed Zaher
}
Applies OCP
/ / CreditCard logic
/ / PayPal logic
}
}
paymentMethod.ProcessPayment(amount);
Ensure subclasses behave correctly when used in place of their parent class. Ahmed Zaher
Violates LSP
/ / Flying logic
Applies LSP
Ahmed Zaher
public abstract class Bird
{
/ / Flying logic
/ / Running logic
}
}
🔧 All subclasses can now be used interchangeably via Move() without causing errors.
Ahmed Zaher
4. Interface Segregation Principle (ISP)
What It Means:
Clients should not be forced to depend on interfaces they don’t use.
❌ Violates ISP
void Work();
✅ Applies ISP
void Work();
}
Ahmed Zaher
public class Human : IWorkable , IFeedable
{
❌ Violates DIP
Applies DIP
/ / Payment logic
}
} Ahmed Zaher
public class PaymentProcessor
{
private readonly IPaymentMethod _paymentMethod;
{
_paymentMethod.Process(amount);
}
}
🔧 The PaymentProcessor depends on abstraction, not on concrete classes. Easier to switch implementations (e.g., to
PayPal or Crypto).
Final Summary
// [ Required ]
[MinLength(2,ErrorMessage ="Name Must be greater than 2 char " )]
[MaxLength(25)]
[Unique]
public s t ring Name { get ; set ; }
[ForeignKey("Department")]
[Display(Name="Department")]
public i n t DepartmentID { get ; set ; }
2- Employee Repository:
Employee Interface
Employee Repository
Ahmed Zaher
public class EmployeeRepository:IEmployeeRepository
{
ITIContext context ;
public EmployeeRepository()
{
context = new ITIContext ();
}
//CRUD
public void Add(Employee obj )
{
context .Add( obj );
}
public void Update(Employee obj )
{
context .Update ( obj );
/ / Actions to implement
After this implementation we have a problem that the Controller Factory can't create an instance of EmployeeRepository to
pass it as a parameter to the controller constructor because :
The EmployeeController needs an IEmployeeRepository passed into its constructor.
But ASP.NET MVC by default does not know how to create an IEmployeeRepository .
So the Controller Factory (the part that creates controllers) throws an error because it can't build
EmployeeController automatically
Resolve Ask the IoC container to give you an instance Controller constructor parameter:
of a registered service. (Happens EmployeeController (IEmployeeRepository repo)
automatically in Controllers.)
Dispose Free or clean up objects after they finish. This The container disposes your repository instance after the request
happens automatically if you use DI properly. ends.
quick summary:
Step Action
Register Add service to the container.
Resolve Get an instance when needed (e.g., in controller constructor).
Dispose Automatically clean up the service after use.
Services Type
Ahmed Zaher
Type Declared Registered Example
Custom Services Not declared Not Registered AddTransient<>()
AddScoped<>()
AddSingleton <>()
1- Register
it's Called by the host before the Configure method to configure the app's services
app.Run();
}
You're telling the ASP.NET Core Dependency Injection (DI) container that when a class (like a controller) requests an instance
of IEmployeeRepository , the container should create (resolve) an instance of EmployeeRepository .
In this constructor, ASP.NET Core uses dependency injection to automatically provide an instance of IEmployeeRepository
when creating the EmployeeController , as long as the service is properly registered in the DI container.
2- inject by Action
When you use Action Injection in a controller, the [FromServices] attribute tells the Dependency Injection (DI) system to
inject the service directly into the action parameter, ignoring any model binding that might otherwise be used.
Ahmed Zaher
examples :
3 - Inject by View
Note:
Before we talk about injecting services into a view, we can make the Repository folder easier to access everywhere by
creating a global using.
To do this, add the following line (for example, in a GlobalUsings . cs file): Ahmed Zaher
global using MVC.Repository;
This way, you don't need to manually add using MVC.Repository; in every file — it becomes automatically available across
the whole project.
Note:
I d = Guid.NewGuid().ToString(); it returns unique id every time You call it .
public EmployeeRepository()
{
context = new ITIContext ();
}
the context = new ITIContext (); inside the constructor of EmployeeRepository violates the Dependency Injection (DI)
principle. In a Dependency Injection pattern, dependencies (like the ITIContext ) should be provided externally, rather than
being created inside the class. This allows for easier testing, better flexibility, and separation of concerns.
Ahmed Zaher
In this case, you should inject the ITIContext into the constructor of EmployeeRepository instead of creating it directly in
the constructor by:
1 - We're using appsettings . json to store the connection string, which is a great approach to avoid hardcoding sensitive
information like database credentials. The configuration in appsettings . json should look like this:
{
"L ogging ": {
"L og L evel ": {
"D ef a ult ": " Information " ,
"M i c rosoft .A sp N et C ore ": "Warning"
}
},
"A llowed H osts ": "*",
"C onne c tion S trings ": {
" c s " : "Data Source = .; Initial Catalog = ITI ; Integrated Security = True ; Encrypt = False ; Trust Server
Certificate = True "
}
}
2- adding a constructor to our ITIContext class that accepts DbContextOptions is required to use the configuration provided
through the appsettings . json file. The goal here is to pass the configuration (e.g., connection string) to the DbContext via the
DbContextOptions :
This constructor ensures that ITIContext can be configured using the DbContextOptions that will be set up via the DI
container. Ahmed Zaher
3- In your Program.cs or Startup . cs (depending on your ASP.NET Core version), you're registering ITIContext in the DI
container. The UseSqlServer method will use the connection string from appsettings . json :
/ / Other s erv i c e s . . .
/ / Other middleware...
}
}
4- our EmployeeRepository now has the ITIContext injected via its constructor:
Key Points:
Appsettings.json: The connection string is pulled from the configuration, so no hardcoding is needed.
DbContext Constructor: The ITIContext constructor is modified to accept DbContextOptions .
DI Registration: In Program.cs or Startup . cs , ITIContext is registered with the DI container using AddDbContext .
Repository Constructor: EmployeeRepository accepts ITIContext via constructor injection.
Note :
The method builder . Services . AddDbContext < ITIContext > ( options => { . . . }) registers the DbContext (in this case
ITIContext ) in the Dependency Injection (DI) container. Once you register the DbContext , it can be injected into any
service or class that requires it.
AddDbContext registers the DbContext to be injected into classes that depend on it. In other words, you cannot directly use
ITIContext unless the class is being injected via Dependency Injection.
in custom validation, use the default constructor ( public ITIContext () : base() ), and you don't use DI to inject the
context, it will work properly but it violates DI , We apply it by :
Day 8
1 - Filters
1 A filter is a block of code that executes before, after, or around the execution of an action method, result, or other
parts of the request pipeline.
2 Filters are used to reduce repetitive code by handling cross-cutting concerns such as logging, caching,
authorization, or error handling in a centralized way.
3 Filters can be applied at different scopes: on an action method, on a controller class, or globally at the application
level through configuration.
4 At a low level, a custom filter implements specific filter interfaces such as IAc tion F ilter , IR esult F ilter ,
IE x c eption F ilter , or their async counterparts. All these interfaces inherit from the IF ilter M et a d a t a marker
Ahmed Zaher
interface, which provides metadata about the filter but is not typically implemented directly.
Built-in Filters :
1- Authorization Filters
What they do:
Run before everything else to determine if the current user/request is allowed to continue.
Built-in example:
Ahmed Zaher
[ Authorize ] attribute.
[AllowAnonymous] to skip authorization or Enter As anonymous
Example :
[ Authorize ]
public class SecureController : Controller
{ public IActionResult Secret ()
{ return View();
}
}
2- Action Filter
The action filter is one of the most common ways to build your own custom filter in ASP.NET Core.
When you want to create a filter that runs code before and/or after your action method, you typically implement:
This allows you to inject custom behavior around the action method execution.
Logging
Validation
Modifying input/output Ahmed Zaher
Measuring execution time
Adding headers, etc.
Instead of repeating this logic in every action, you write it once in a filter.
Example :
1- OnActionExecuting
What it does:
Runs before the action method is executed.
This is where you can add custom logic before the action runs (e.g., validation, logging, modifying parameters, or even
redirecting).
Parameters:
ActionExecutingContext context: This object provides information about the action being executed, such as:
Ahmed Zaher
The action descriptor (details about the action method).
The action parameters (input data passed to the action). as Key Value Pair
2 OnActionExecuted
What it does:
Runs after the action method has executed, but before the result is executed (i.e., before the action's return value is
processed by any result filters or sent back to the client).
This is where you can perform post-action processing (e.g., logging the result, modifying the result, error handling).
Parameters:
ActionExecutedContext context: This object provides information about the executed action:
The action descriptor (details about the executed action).
The action result (the result returned by the action, such as ViewResult , JsonResult , etc.).
3- Result Filters
What they do:
Run before and after the result (e.g., a View or JSON response) is processed. Used to change the result or log view rendering.
Built-in example:
No common standalone result filters, but ResponseCache acts partly at this level.
Example:
At Home Controller :
It controls caching behavior of the HTTP response by setting appropriate cache-related headers.
4- Exception Filter
Job:
Example :
Another Example :
Ahmed Zaher
viewResult.ViewData["msg"] = msg;
context . Result = viewResult ;
}
}
We must Inherit First from Attribute class then IExceptionFilter interface , to use it as attribute
At Controller:
[ ErrorClass ]
public IActionResult TestError ()
{
throw new Exception ( " Test exception " );
}
Note :*
ViewName = " Error " means using Error View that is at Shred File
At Program.cs
Ahmed Zaher
Sometimes We need to add layer between Repository and model called Service to make mapping
We Need To Know What Are Identity Classes?
In ASP.NET Core Identity, Microsoft provides a set of built-in classes that help you manage authentication and
authorization out of the box.
Class Purpose
IdentityUser Represents a user account (e.g., a person who logs in).
IdentityRole Represents a role (e.g., Admin, User, Manager).
IdentityDbContext The Entity Framework DbContext that contains the tables to store users, roles, etc.
Ahmed Zaher
Class Purpose
UserManager<TUser> A service to create, update, delete, and manage users.
RoleManager<TRole> A service to create, update, delete, and manage roles.
SignInManager<TUser> Handles login, logout, and authentication logic && Stores the user's claims in the cookie for
future requests.
UserStore<TUser> Implements IUserStore and works with EF Core to save users in DB.
RoleStore <TRole > Implements IRoleStore and works with EF Core to save roles in DB.
then :
UserManager--(deals with)-->UserStore--(deals with)-->IdentityDBContext
IdentityUser has :
In IdentityUser , the I d property is inherited directly from the base class and is used as the primary key for each user in
the database.
Where is I d Defined?
It's defined like this:
When you use the non-generic version IdentityUser (i.e., IdentityUser without <TKey> ), it defaults to string :
Ahmed Zaher
If you need extra custom fields (e.g., FullName, DateOfBirth), you can inherit from IdentityUser and Make a New Class to
follow Open for Extend Close for Modification :
}
/ / Required
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); Ahmed Zaher
}
}
We Make it Generic to Apply New Attributes (Attribute For Generic Must inherit from identityDbContext )
After that we add migration and add update the database
Now We Finished Our Classes and DataBase
We will make the Controller and ViewModel for mapping , because we don't need to
enter all IdentityUser properties
1- ViewModel:
[DataType(DataType.Password)]
public s t ring Password { get ; set ; }
[Compare("Password")]
[Display(Name ="Confirm Password")]
[DataType(DataType.Password)]
public s t ring ConfirmPassword { get ; set ; }
public AccountController
( UserManager <ApplicationUser > userManager , SignInManager < ApplicationUser > signInManager )
{
this . userManager = userManager;
this . signInManager = signInManager ;
}
[ HttpPost ]
public async Task < IActionResult > SaveRegister
(RegisterUserViewModel UserViewModel)
{
i f ( ModelState . IsValid )
{
//Mapping
ApplicationUser appUser = new ApplicationUser ();
appUser.Address = UserViewModel.Address;
appUser.UserName = UserViewModel.UserName;
// save database
IdentityResult res ult =
await userManager.CreateAsync (appUser, UserViewModel.Password);
i f ( result . Succeeded )
{
// Cookie
await signInManager . SignInAsync ( appUser , f a lse );
return RedirectToAction ( " Index " );
} Ahmed Zaher
foreach ( var item i n result . Errors )
{
ModelState .AddModelError ("", item . Description );
}
}
return View ( " Register " , UserViewModel);
}
}
Both are injected via Dependency Injection (IoC container) and are ready to use in your controllers or services.
Remember :
UserManager Used For CRUD operations , SignInManager for adding Cookies
CreateAsync :
Adds the user to the database.
Automatically hashes the password and saves it securely.
returns IdentityResult that is a result object that tells you whether the operation succeeded or failed.
When you pass the password to CreateAsync() , it hashes it immediately using a secure algorithm (by default,
PBKDF2 with HMAC-SHA256).
The result (the hash) is saved in the PasswordHash column in the AspNetUsers table.
It has two key members:
Ahmed Zaher
Property Purpose
Succeeded A bool: true if the user was created successfully; fals e if there were any errors.
Errors A collection of IdentityError objects that explain what went wrong (if any errors).
Note : Because of CreateAsync is Async We Add await and Convert *Action To Task
SignInAsync
Sign in the user ( appUser ) and create an authentication cookie to keep them logged in.
Part Meaning
appUser The user object (of type ApplicationUser ) you just created or fetched.
false This is is P ersistent : it tells whether the login session (cookie) should be persistent. (The login
session will end when the browser is closed.)
3- At Program.cs
Ahmed Zaher
builder . Services . AddIdentity < ApplicationUser , IdentityRole > (). AddEntityFrameworkStores < ITIContext > ();
this line adds Identity services with your user ( ApplicationUser ) and role ( IdentityRole ).
It also registers UserManager, SignInManager, RoleManager, etc. for Dependency Injection automatically.
Part Meaning
AddIdentity < ApplicationUser , IdentityRole > 🔧 You're telling ASP.NET:
()
- ApplicationUser : your custom user class (inherits from
IdentityUser ).
- IdentityRole : the default class to handle roles (like Admin, User, etc.).
.AddEntityFrameworkStores<ITIContext>() 🔗 You’re telling Identity to use your Entity Framework DbContext
( ITIContext ) to store users/roles.
Ahmed Zaher
Instead Of Build The View From Scratch We Have Built-in Template We Can Use
Ahmed Zaher
I chose the Template and the ViewModel That will apply for it
the steps that is listed form the core sequence to implement an authentication module using ASP.NET Core Identity with
Entity Framework Core. However, to ensure your authentication module is complete and functional, :
1. Install package Identity "Microsoft.AspNetCore.Identity.EntityFrameworkCore"
2. class ApplicationUser : IdentityUser
3. ITIContext : IdentityDbContext < ApplicationUser >
Ahmed Zaher
4. Add-migration
5. Create AccountController (Adding user manager , sign in manager by DI)
6. Create RegisterViewModel
7. Register Action
8. Register IdentityService in Program class
Note :
So, it's responsible for checking and loading who the user is.
[Authorize] :
What does it do?
After UseAuthentication () finishes and has loaded the user info, [ Authorize ] comes in and says:
[ HttpPost ]
[ ValidateAntiForgeryToken ]
public async Task < IActionResult > SaveLogin(LoginUserViewModel userViewModel)
{
i f ( ModelState . IsValid == true )
{
// check found
ApplicationUser appUser=
await userManager.FindByNameAsync(userViewModel.Name);
Ahmed Zaher
i f (appUser != null )
{
bool found=
await userManager.CheckPasswordAsync (appUser, userViewModel.Password);
if ( found == true )
{
await signInManager.SignInAsync(appUser,userViewModel.RememberMe);
return RedirectToAction ( " Index " , "Department");
}
}
ModelState.AddModelError("", "Username OR PAssword wrong");
// create cookie
}
return View ( " Login " , userViewModel);
}
ApplicationUser appUser=
await userManager.FindByNameAsync(userViewModel.Name);
it returns the User of ApplicationUser type if Found it , if not will return null
Controllers in ASP.NET Core inherit some properties from the ControllerBase or Controller class (depending on the type
of controller). These properties are automatically available to the controller without any additional setup. Specifically:
1- ViewData
Ahmed Zaher
2 ViewBag
The User property represents the current authenticated user. It contains information about the user's identity and
claims (like roles, email, etc.), If No Authentication Found it Becomes N ull
Inheritance: User is inherited from ControllerBase (which is the base class for controllers).
Cl a ims Prin cip a l :
In ASP.NET Core, C l a ims P rin c ip a l is the class used to represent the current authenticated user and contains
all the claims associated with that user. The claims provide key information about the user, such as their roles,
email address, and any other custom attributes related to their identity.
C l a ims P rin c ip a l provides:
1 Identity: Basic information about the user (like username).
2 Claims: A collection of key-value pairs containing the user's information, such as roles, permissions, email, etc.
Example :
Claim AddressClaim = User . Claims . FirstOrDefault ( c => c.Type == " UserAddress " );
User . Identity . IsAuthenticated == true Used To Get The Authentication like `[Authorize]
s t r ing name = User.Identity.Name; used to get the Name
To Get Other Properties by :
We Deal With User as context , Claims as Class in it , then use the needed property
Claims returns Type of IEnumerable
NameIdentifier is part of standard identity claims but "UserAddress" is A Custom Claim
Claim AddressClaim = User . Claims . FirstOrDefault ( c => c.Type == " UserAddress " );
Example:
1 Identity :
2 Claims :
Country ClaimTypes.Country US
Locality (City) ClaimTypes . Locality New York
Street Address ClaimTypes.StreetAddress 123 Main St
List < Claim > Claims = new List < Claim > ();
Claims.Add(new Claim ( " UserAddress " ,appUser .Address ));
To get it :
Ahmed Zaher
var userAddress = User . FindFirst ( " UserAddress " )?. Value ;
// or
Claim AddressClaim = User . Claims . FirstOrDefault ( c => c.Type == " UserAddress " );
IdentityResult result =
await userManager.CreateAsync(appUser,UserViewModel.Password); Ahmed Zaher
i f ( result . Succeeded )
{
// assign to role
await userManager.AddToRoleAsync(appUser, "Admin");
/ / or
await userManager.AddToRolesAsync (appUser, new[] { "Admin", "Manager" });
// Cookie
await signInManager . SignInAsync ( appUser , f a lse );
return RedirectToAction ( " Index " , "Department");
}
If you want to restrict access so that only users in the Admin role can access a controller or an action, you use:
At login time:
The system queries that table to find out which roles the user belongs to (following those foreign key links).
It creates claims for each role and loads them into the user’s identity (ClaimsPrincipal).
Those claims are stored in the authentication cookie (or token).
Roles → Claims → ClaimsPrincipal → User.
On every request:
The ClaimsPrincipal is rebuilt from the cookie/token and made available via User in controllers.
After login:
Important reminder:
If you assign a role to a user after they’ve already logged in, the user won’t see the new role until they log out and log in
again, unless you force the claims to refresh.
Ahmed Zaher
Day 9
1- Partial View:
How to create:
@model Employee
Because:
The partial view is injected into a main view.
The main view already has the full layout:
HTML <head> , <body> , title, scripts, styles, etc.
The partial view is meant to focus only on the small section of content it is responsible for.
As we see it can easy take a Model
To include a Partial View in the Main View:
Ahmed Zaher
@{
Html . RenderPartial ( "_ NavPartial " );
// or
await Html . RenderPartialAsync ( "_ NavPartial " );
}
✅ Notes:
2️⃣ Using Tag Helper ( recommended for Razor Pages and MVC):
Note:
by default A partial view will inherit the model from the parent (main) view unless you explicitly pass a different model.
1- By Tag Helper :
2- By Html Helper :
Ahmed Zaher
AJAX Request
it's used to update part of the page without reloading the whole thing.
But technically:
The HTTP request itself is a full request.
When you send an AJAX request using XMLHttpRequest , it goes through the full HTTP pipeline:
The browser sends full HTTP headers, cookies, and body (if applicable).
The server (like ASP.NET) sees it as a normal HTTP request.
What makes it feel "partial" is how you handle the response on the client side.
Instead of reloading the whole page (like with a normal form submission),
Ahmed Zaher
You use JavaScript to update just part of the page (e.g., a < div > , a table, a form section)
XmlHttpRequest:
➔ This is the JavaScript object that creates and manages AJAX requests. and received XML or JSON
js "Dom":
➔ After the response is received, JavaScript updates the DOM (HTML content) dynamically.
CSS:
➔ You can also manipulate CSS (styles) as part of the dynamic update.
To implement Ajax :
@model List<Employee>
@{
ViewData [ " Title " ] = " Index " ;
}
<h1>Index</h1>
<a asp - action="New" asp - controller="Employee">NEw</a> Ahmed Zaher
< div id = " div 1 " style = " border : 2 px s o l i d blue " ></ div >
< script src = " ~ / lib / jquery / dist / jquery . js " ></ script >
< script >
function GetEmpData(EmpID) {
event . preventDefault ();
Ahmed Zaher
// Ajax C all Endpont using jquery
$.ajax({
u r l : "/Employee/EmpCardPartial/" + EmpID,
s u c c e s s : function ( res ult ) {
console . log ( result );
$( "#div 1" ).html( result );
}
});
}
</ script >
$.ajax({
u r l : "/Employee/EmpCardPartial/" + EmpID,
s u c c e s s : function ( res ult ) {
console . log ( result );
$( "#div 1" ).html( result );
}
});
We put Wanted URL that doing fetch from ,and Dom for Wanted Div
So We have made an ajax Call
Ahmed Zaher
Example using AJAX :
1- I want to make 2 drop-down lists , one for Department and other for Employees
at selected department
1 Employee
2 at Department Controller
3 at Department View
@model List<Department>
@{
ViewData [ " Title " ] = "DeptEmps";
}
< script src = " ~ / lib / jquery / dist / jquery . min . js " ></ script >
< script >
function GetEmp() {
var deptID = document.getElementById("DeptId").value;
var empElement = document.getElementById("Emps");
empElement.innerHTML = "" ;
console . log ( deptID );
// Ajax c a l l json
$.ajax({
u r l : "/DEpartment/GetEmpsByDEptId?deptId=" + deptID
, s u c c e s s : function ( res ult ) {
console . log ( result )
for ( l e t emp of res ult ) {
empElement.innerHTML += " < option value = '" + emp.id + "' > " + emp.name + " < / option > " ;
}
}
});
}
</ script >
Ahmed Zaher
First We Loaded All Departments, and use onChange() to every time I change the selected department I load it's employees
by GetEmp() function
< select id = " DeptId " name="DeptID" class = " form form-control " onchange="GetEmp()">
@foreach(var deptItem i n Model){
< option value="@deptItem.Id">@deptItem.Name</option>
}
</ select >
Then We make an Empty Select To load all Employee Related To Selected Department
< select id="Emps" name="Emps" class = " form form-control " ></ select >
We use Jquery
< script src = " ~ / lib / jquery / dist / jquery . min . js " ></ script >
< script >
function GetEmp() {
var deptID = document.getElementById("DeptId").value;
var empElement = document.getElementById("Emps");
empElement.innerHTML = "" ;
console . log ( deptID );
// Ajax c a l l json
$.ajax({
u r l : "/DEpartment/GetEmpsByDEptId?deptId=" + deptID
, s u c c e s s : function ( res ult ) {
console . log ( result )
for ( l e t emp of res ult ) {
empElement.innerHTML += " < option value = '" + emp.id + "' > " + emp.name + " < / option > " ;
}
} Ahmed Zaher
});
}
</ script >
r e s ul t s the data returned by the server when the AJAX request completes successfully.
Routing
What is Routing :
routing refers to the system that maps incoming HTTP requests to specific code—typically controllers, actions,
Razor pages, or endpoints.
What it means:
When a user visits a URL like / products / details / 5 , routing figures out which controller and action (or page) should
handle that request.
The routing system parses the URL and binds parameters (like the 5 in the example) to your method’s parameters.
1 convention-based routing :You can use convention-based routing (via route templates like
{controller}/{action}/{id?} )
2 attribute routing (via [Route()] attributes).
Ahmed Zaher
1- Convention-based routing
We need to know about URL
1 / ➔ called a delimiter
2 /.../ or /emp/ ➔ called Segmrnt
so , Convention-based routing means:
You define a general pattern (a convention) that tells ASP.NET how to map URLs to controller actions.
URLs that follow this pattern automatically map to your code without needing special route definitions for each one.
pattern
pattern : "{controller}/{action}/{id?}"
1️⃣ Placeholders
2️⃣ Literals
➡ Examples:
Example pattern:
`"{controller}/{action}/{id?}"`
➡ Examples:
app.UseRouting ();
This adds the routing middleware to the pipeline. It tells ASP.NET Core:
“We are going to process incoming URLs and match them to routes.”
At Route Controller
The first parameter of MapControllerRoute() is a name for the route. In this case, "Route2" is simply a name for the route
being defined , it must be unique.
we use :
Ahmed Zaher
/R2?name=ali
like :
Ahmed Zaher
app.MapControllerRoute ("Route 2", "R2/{name}/{age:int}",
new { controller = "Route", action = "Method2" }
);
makes third segment name must be same for for method attribute
like :
Here We can use Controller , Action For URL , it is the default for Microsoft so , We can put it at last
[Route("M1/{age:int}/{name?}",Name ="R1")]
public IActionResult Method 1()// string name,int age)
{
return Content("M1");
}
Note:
**Attribute-based routing : used Most For API
2 Convention-based routing : Used Most For MVC
Ahmed Zaher
Connect with me :-
Ahmed Zaher Ahmed Zaher
Ahmed Zaher
Thank
You
Ahmed Zaher