.NET ProgrammingUnit 810 min read
ASP.NET Core: MVC, Razor Pages, Middleware & Deployment
Unit 8 of .NET Programming covers ASP.NET Core’s architecture, Model-View-Controller (MVC) pattern, Razor Pages, middleware pipeline, dependency injection, and deployment strategies (IIS, Docker, Azure). It explains how to build scalable web apps with routing, filters, and real-world hosting.
ASP.NET Core Architecture Overview
ASP.NET Core is a cross-platform, high-performance framework for building modern web apps. It is modular, lightweight, and supports:
- Cross-platform: Runs on Windows, Linux, and macOS.
- Modular: Only include what you need (e.g., MVC, Razor Pages, Web API).
- Dependency Injection (DI): Built-in support for DI via
IServiceProvider. - Middleware Pipeline: Requests pass through a chain of middleware components (e.g., authentication, logging).
Key Components
classDiagram
class ASPNETCore {
+Middleware Pipeline
+Dependency Injection
+Routing
+Configuration
+Logging
+Razor Pages
+Controllers
}
class Middleware {
<<interface>>
+Invoke(HttpContext context)
+InvokeAsync(HttpContext context)
}
class Controller {
<<abstract>>
+ActionResult Index()
+[static] OnActionExecuting()
}
class RazorPage {
<<class>>
+OnGet()
+OnPost()
}
class Model {
<<class>>
+Properties
+Validation
}
class View {
<<class>>
+Render(Model model)
+Partial Views
}
ASPNETCore --> Middleware : "Uses Pipeline"
ASPNETCore --> Controller : "Contains"
ASPNETCore --> RazorPage : "Contains"
Controller --> Model : "Uses"
Controller --> View : "Returns"
RazorPage --> Model : "Uses"
RazorPage --> View : "Renders"
Middleware --> Middleware : "Chains"Updated class diagram showing MVC + Razor Pages relationship with ASP.NET CoreModel-View-Controller (MVC) Pattern
MVC separates an application into three interconnected components:
- Model: Manages data and business logic (e.g.,
DbContext, entities). - View: Displays UI (Razor views,
.cshtmlfiles). - Controller: Handles HTTP requests, processes data, and returns views.
Worked Example: Simple MVC Flow
Scenario: A blog app where users view posts.
// Model (BlogPost.cs)
public class BlogPost {
public int Id { get; set; }
public string Title { get; set; }
public string Content { get; set; }
}
```figure
{"type":"network","nodes":["User","Controller","Model","View","Database"],"edges":[["User","Controller",{"label":"HTTP Request"}],["Controller","Model",{"label":"Fetch Data"}],["Model","Database",{"label":"Query"}],["Database","Model",{"label":"Result"}],["Controller","View",{"label":"Render"}],["View","User",{"label":"Response"}]],"caption":"Complete MVC request-response cycle with database interaction"}
// Controller (PostsController.cs) public class PostsController : Controller { public IActionResult Index() { var posts = new List<BlogPost> { new BlogPost { Id = 1, Title = "First Post", Content = "Hello!" } }; return View(posts); // Renders Index.cshtml } }
// View (Index.cshtml) @model List<BlogPost>
<h1>Blog Posts</h1> <ul> @foreach (var post in Model) { <li>@post.Title</li> } </ul>Trace:
| Step | Action | State After Step |
|---|---|---|
| 1 | User visits /Posts/Index |
Request reaches PostsController.Index() |
| 2 | Controller fetches BlogPost |
posts list populated |
| 3 | return View(posts) |
Razor engine renders Index.cshtml |
| 4 | View displays HTML | User sees rendered page |
Razor Pages
Razor Pages is a simpler alternative to MVC for page-focused apps. Key features:
- Page-based: Each
.cshtmlfile is a self-contained page with a code-behind file (.cs). - No controllers: Logic is embedded in the page.
- Tag Helpers: HTML-like syntax for server-side logic (e.g.,
@Html.TextBox).
Example: Razor Page for User Login
File: Login.cshtml
@page
@model LoginModel
<h1>Login</h1>
<form method="post">
<input asp-for="Username" />
<input asp-for="Password" type="password" />
<button type="submit">Login</button>
</form>
Code-behind: Login.cshtml.cs
public class LoginModel : PageModel {
[BindProperty]
public string Username { get; set; }
public string Password { get; set; }
public void OnGet() { }
public IActionResult OnPost() {
if (Username == "admin" && Password == "123") {
return RedirectToPage("/Dashboard");
}
return Page(); // Re-renders with errors
}
}
Trace:
| Step | Action | State After Step |
|---|---|---|
| 1 | User submits form | OnPost() triggered |
| 2 | Validates credentials | Username and Password bound |
| 3 | Redirects to /Dashboard |
User navigates to secure page |
Middleware Pipeline
Middleware components process HTTP requests/responses in a pipeline. Common middleware:
- Authentication:
JwtBearer,CookieAuthentication. - Logging:
ILogger. - Error Handling:
ExceptionHandler. - Static Files:
StaticFilesMiddleware.
Example: Custom Middleware for Logging
public class LoggingMiddleware {
private readonly RequestDelegate _next;
public LoggingMiddleware(RequestDelegate next) {
_next = next;
}
public async Task InvokeAsync(HttpContext context) {
Console.WriteLine($"Request: {context.Request.Path}");
await _next(context); // Pass to next middleware
Console.WriteLine($"Response: {context.Response.StatusCode}");
}
}
Register in Program.cs:
app.UseMiddleware<LoggingMiddleware>();
Trace:
flowchart TD
A["Request"] --> B["LoggingMiddleware: Logs path"]
B --> C["Next Middleware"]
C --> D["Response"]
D --> B["LoggingMiddleware: Logs status"]Dependency Injection (DI)
ASP.NET Core’s built-in DI simplifies managing services (e.g., DbContext, ILogger). Register services in Program.cs:
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddTransient<IEmailService, EmailService>();
Example: Injecting IUserRepository into a controller.
public class UsersController : Controller {
private readonly IUserRepository _repo;
public UsersController(IUserRepository repo) {
_repo = repo;
}
public IActionResult Index() {
var users = _repo.GetAll();
return View(users);
}
}
Routing
Routing maps URLs to controllers/actions. Default conventions:
/Controller/Action/Id→Controller.Action(int id).- Attribute routing:
[Route("api/[controller]")].
Example: Custom route for a blog.
[Route("api/posts/{id}")]
public class PostsController : Controller {
[HttpGet]
public IActionResult Get(int id) {
return Ok(new { Id = id, Title = "Sample Post" });
}
}
Trace:
| URL | Action | Output |
|---|---|---|
/api/posts/1 |
Get(1) |
{ "Id": 1, "Title": "Sample" } |
In the Real World
eSewa (Nepal):
- Uses ASP.NET Core for its backend API to handle online bill payments (electricity, telecom).
- Middleware: Validates user sessions and logs transactions.
- Razor Pages: Admin dashboard for viewing payment records.
Khalti (Nepal):
- Employs MVC pattern to separate payment processing (Model), UI (View), and request handling (Controller).
- Dependency Injection: Manages services like
IPaymentGatewayfor seamless integrations.
YouTube (Global):
- Built on ASP.NET Core (via .NET’s influence on modern web stacks).
- Middleware Pipeline: Handles authentication (OAuth), rate limiting, and caching.
- Routing: Maps
/watch?v=abc123to video retrieval logic.
Deployment Strategies
Deploy ASP.NET Core apps to:
- IIS (Windows): Use
web.configand publish as a folder. - Docker: Containerize apps for consistency across environments.
- Azure App Service: Fully managed PaaS with auto-scaling.
Example: Dockerfile for ASP.NET Core.
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["ASP.NETCoreApp.csproj", "."]
RUN dotnet restore "ASP.NETCoreApp.csproj"
COPY . .
RUN dotnet publish "ASP.NETCoreApp.csproj" -c Release -o /app/publish
FROM build AS publish
RUN dotnet publish "ASP.NETCoreApp.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "ASP.NETCoreApp.dll"]
Trace:
| Step | Action | Output |
|---|---|---|
| 1 | docker build -t myapp . |
Container image built |
| 2 | docker run -p 8080:80 myapp |
App runs on http://localhost:8080 |
Exam Tip
MVC vs. Razor Pages:
- MVC is better for complex apps with many controllers.
- Razor Pages is simpler for page-focused apps (e.g., admin panels).
- Exam Pitfall: Confusing
ViewBag/ViewData(dynamic) vs. strongly typed models.
Middleware Order:
- Middleware runs top-to-bottom in
Program.cs. Example:app.UseHttpsRedirection(); // Must be first for HTTPS app.UseStaticFiles(); // Serve static files app.UseRouting(); // Enable endpoint routing - Exam Question: "Why does
UseRouting()fail if placed beforeUseEndpoints()?"
- Middleware runs top-to-bottom in
DI Scopes:
Transient: New instance per request.Scoped: One instance per HTTP request.Singleton: One instance for the app lifetime.- Exam Question: "When would you use
ScopedforDbContext?"
Routing:
- Memorize attribute routing syntax:
[Route("api/[controller]")]. - Exam Question: "How would you map
/products/{category}to a controller?"
- Memorize attribute routing syntax:
Deployment:
- Know the difference between self-contained (includes .NET runtime) and framework-dependent deployments.
- Exam Question: "Why might you choose Docker over IIS for deployment?"
Based on the TU BITM syllabus for .NET Programming (IT275), unit 8.
Discussion
Loading…