Welcome to Module 10 of our ASP.NET Core Complete Course: Beginner to Advanced Guide for Modern Web Development. In this module, we dive deep into Advanced ASP.NET Core Features, exploring powerful tools and techniques to build sophisticated, scalable, and maintainable web applications. This comprehensive, SEO-friendly guide covers Middleware Deep Dive, Filters in MVC (Action, Authorization, Exception), Custom Tag Helpers & View Components, Background Services with IHostedService, and Localization & Globalization.
Packed with practical examples, detailed explanations, real-world scenarios, pros and cons, alternatives, and best practices for security, performance, and error handling, this blog post will equip you with the skills to leverage ASP.NET Core’s advanced capabilities. Whether you're a beginner or an advanced developer, this module will help you master these features to create professional-grade applications. Let’s get started!
Table of Contents
Introduction to Advanced ASP.NET Core Features
Middleware Deep Dive
What is Middleware?
Pros, Cons, and Alternatives
Example: Creating Custom Middleware
Filters in MVC (Action, Authorization, Exception)
Understanding Filters
Pros, Cons, and Alternatives
Example: Implementing Filters
Custom Tag Helpers & View Components
What are Tag Helpers and View Components?
Pros, Cons, and Alternatives
Example: Building Custom Tag Helpers and View Components
Background Services with IHostedService
What is IHostedService?
Pros, Cons, and Alternatives
Example: Implementing a Background Service
Localization & Globalization
Understanding Localization and Globalization
Pros, Cons, and Alternatives
Example: Implementing Localization
Best Practices for Advanced ASP.NET Core Features
Security Best Practices
Performance Best Practices
Error Handling Best Practices
Real-Life Example: Building an E-Commerce Dashboard
Conclusion
FAQs
Introduction to Advanced ASP.NET Core Features
ASP.NET Core offers a rich set of advanced features that enable developers to build flexible, maintainable, and globally accessible web applications. These features include middleware for request processing, filters for MVC logic, tag helpers and view components for reusable UI, background services for long-running tasks, and localization for multi-language support.
In Module 10, we’ll explore:
Middleware Deep Dive: Customizing the request pipeline.
Filters in MVC: Managing action execution, authorization, and exceptions.
Custom Tag Helpers & View Components: Enhancing UI reusability.
Background Services with IHostedService: Running background tasks.
Localization & Globalization: Supporting multiple languages and cultures.
This blog post includes detailed explanations, practical examples, pros and cons, alternatives, and best practices for security, performance, and error handling. We’ll also build a real-life e-commerce dashboard to demonstrate these concepts in action.
Why is this important?
Middleware: Allows fine-grained control over HTTP requests.
Filters: Streamline cross-cutting concerns in MVC applications.
Tag Helpers & View Components: Simplify UI development with reusable components.
Background Services: Enable asynchronous, long-running tasks.
Localization: Makes applications accessible to global audiences.
Let’s dive into each topic with detailed explanations and real-world examples.
Middleware Deep Dive
What is Middleware?
Middleware in ASP.NET Core is software that processes HTTP requests and responses in a pipeline. Each middleware component can handle a request, modify it, short-circuit the pipeline, or pass it to the next component.
Key Features
Pipeline: Middleware forms a chain, executed in the order defined.
Request/Response Handling: Can inspect, modify, or terminate requests.
Customizable: Developers can create custom middleware for specific needs.
Built-in Middleware: Includes authentication, routing, static files, etc.
Pros, Cons, and Alternatives for Middleware
Pros
Flexibility: Customize the request pipeline for specific requirements.
Modularity: Each middleware handles a single responsibility.
Reusable: Middleware can be reused across projects.
Built-in Support: ASP.NET Core provides robust middleware APIs.
Cons
Complexity: Incorrect middleware ordering can cause issues.
Performance: Poorly written middleware can slow down the pipeline.
Debugging: Errors in middleware can be hard to trace.
Alternatives
Filters: For MVC-specific logic (e.g., authorization, exception handling).
Global Handlers: For application-wide logic without middleware.
Custom Endpoints: Use Minimal APIs for lightweight request handling.
Example: Creating Custom Middleware
Let’s create custom middleware to log request details and restrict access based on IP addresses.
Step 1: Create a New MVC Project
dotnet new mvc -o AdvancedApp
cd AdvancedApp
Step 2: Create Custom MiddlewareCreate Middleware/RequestLoggingMiddleware.cs:
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
namespace AdvancedApp.Middleware
{
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
_logger.LogInformation($"Request: {context.Request.Method} {context.Request.Path} from {context.Connection.RemoteIpAddress}");
await _next(context);
_logger.LogInformation($"Response: {context.Response.StatusCode}");
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in RequestLoggingMiddleware");
context.Response.StatusCode = 500;
await context.Response.WriteAsync("An error occurred during request processing.");
}
}
}
public static class RequestLoggingMiddlewareExtensions
{
public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder)
{
return builder.UseMiddleware<RequestLoggingMiddleware>();
}
}
}
Create Middleware/IpRestrictionMiddleware.cs:
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
namespace AdvancedApp.Middleware
{
public class IpRestrictionMiddleware
{
private readonly RequestDelegate _next;
private readonly string[] _allowedIps;
public IpRestrictionMiddleware(RequestDelegate next, string[] allowedIps)
{
_next = next;
_allowedIps = allowedIps;
}
public async Task InvokeAsync(HttpContext context)
{
var ip = context.Connection.RemoteIpAddress?.ToString();
if (_allowedIps.Contains(ip))
{
await _next(context);
}
else
{
context.Response.StatusCode = 403;
await context.Response.WriteAsync("Access denied: IP not allowed.");
}
}
}
public static class IpRestrictionMiddlewareExtensions
{
public static IApplicationBuilder UseIpRestriction(this IApplicationBuilder builder, params string[] allowedIps)
{
return builder.UseMiddleware<IpRestrictionMiddleware>(allowedIps);
}
}
}
Step 3: Configure MiddlewareUpdate Program.cs:
using AdvancedApp.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRequestLogging();
app.UseIpRestriction("127.0.0.1", "::1"); // Allow localhost only
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Step 4: Test the MiddlewareRun the application with dotnet run. Access / from localhost (allowed) and another IP (denied). Check logs for request details.
Output (Logs):
info: AdvancedApp.Middleware.RequestLoggingMiddleware[0]
Request: GET / from 127.0.0.1
info: AdvancedApp.Middleware.RequestLoggingMiddleware[0]
Response: 200
This example demonstrates custom middleware for logging and IP restriction, with error handling for robustness.
Filters in MVC
Understanding Filters
Filters in ASP.NET Core MVC allow you to run code before or after specific stages in the request pipeline, such as action execution, authorization, or exception handling.
Types of Filters
Authorization Filters: Run first, checking if the user is authorized.
Action Filters: Run before/after action methods.
Result Filters: Run before/after action results are executed.
Exception Filters: Handle uncaught exceptions.
Resource Filters: Run before model binding or after resource execution.
Pros, Cons, and Alternatives for Filters
Pros
Cross-Cutting Concerns: Handle logging, authorization, and validation centrally.
Reusable: Apply filters globally, at the controller, or action level.
Flexible: Support custom logic for various pipeline stages.
Built-in Support: ASP.NET Core provides robust filter APIs.
Cons
Complexity: Overuse can make code harder to understand.
Performance: Poorly written filters can impact performance.
Order Sensitivity: Incorrect filter ordering can cause issues.
Alternatives
Middleware: For request pipeline-level logic.
AOP (Aspect-Oriented Programming): Using libraries like PostSharp for cross-cutting concerns.
Decorators: Custom attributes for simpler logic.
Example: Implementing Filters
Let’s create authorization, action, and exception filters for an MVC application.
Step 1: Create FiltersCreate Filters/CustomAuthorizationFilter.cs:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
namespace AdvancedApp.Filters
{
public class CustomAuthorizationFilter : IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (!context.HttpContext.User.Identity.IsAuthenticated)
{
context.Result = new UnauthorizedResult();
}
}
}
}
Create Filters/LoggingActionFilter.cs:
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace AdvancedApp.Filters
{
public class LoggingActionFilter : IActionFilter
{
private readonly ILogger<LoggingActionFilter> _logger;
public LoggingActionFilter(ILogger<LoggingActionFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation($"Executing action {context.ActionDescriptor.DisplayName}");
}
public void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception != null)
{
_logger.LogError(context.Exception, "Action failed");
}
else
{
_logger.LogInformation("Action executed successfully");
}
}
}
}
Create Filters/CustomExceptionFilter.cs:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace AdvancedApp.Filters
{
public class CustomExceptionFilter : IExceptionFilter
{
private readonly ILogger<CustomExceptionFilter> _logger;
public CustomExceptionFilter(ILogger<CustomExceptionFilter> logger)
{
_logger = logger;
}
public void OnException(ExceptionContext context)
{
_logger.LogError(context.Exception, "An unhandled exception occurred");
context.Result = new ObjectResult(new { error = "An unexpected error occurred", details = context.Exception.Message })
{
StatusCode = 500
};
context.ExceptionHandled = true;
}
}
}
Step 2: Register FiltersUpdate Program.cs:
using AdvancedApp.Filters;
using AdvancedApp.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<CustomAuthorizationFilter>();
options.Filters.Add<LoggingActionFilter>();
options.Filters.Add<CustomExceptionFilter>();
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRequestLogging();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Step 3: Create a ControllerUpdate Controllers/HomeController.cs:
using Microsoft.AspNetCore.Mvc;
namespace AdvancedApp.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
public IActionResult TestError()
{
throw new Exception("Test exception");
}
}
}
Step 4: Test FiltersRun the application and access / (requires authentication) and /Home/TestError (triggers exception filter). Check logs for action execution details.
Output (Logs):
info: AdvancedApp.Filters.LoggingActionFilter[0]
Executing action AdvancedApp.Controllers.HomeController.Index
info: AdvancedApp.Filters.LoggingActionFilter[0]
Action executed successfully
error: AdvancedApp.Filters.CustomExceptionFilter[0]
An unhandled exception occurred: Test exception
This example demonstrates authorization, action, and exception filters with logging and error handling.
Custom Tag Helpers & View Components
What are Tag Helpers and View Components?
Tag Helpers and View Components are ASP.NET Core features for creating reusable UI elements.
Tag Helpers: Enhance HTML tags with server-side logic, making Razor views cleaner.
View Components: Render reusable UI fragments with complex logic, similar to partial views but more powerful.
Pros, Cons, and Alternatives for Tag Helpers and View Components
Pros
Tag Helpers:
Intuitive: Blend seamlessly with HTML syntax.
Reusable: Encapsulate UI logic for reuse.
Flexible: Support custom attributes and logic.
View Components:
Complex Logic: Handle server-side rendering with business logic.
Reusable: Ideal for widgets or modular UI components.
Independent: Don’t rely on controller context.
Cons
Tag Helpers:
Learning Curve: Requires understanding of tag helper syntax.
Performance: Overuse can impact rendering time.
Debugging: Errors in tag helpers can be hard to trace.
View Components:
Complexity: More complex than partial views.
Overhead: Requires additional setup compared to simple HTML.
State Management: Managing state can be challenging.
Alternatives
Partial Views: For simpler, static UI fragments.
Razor Components: For Blazor applications with interactive UI.
JavaScript Frameworks: Use React or Vue for client-side UI.
Example: Building Custom Tag Helpers and View Components
Let’s create a tag helper for formatting prices and a view component for displaying recent products.
Step 1: Create a Tag HelperCreate TagHelpers/CurrencyTagHelper.cs:
using Microsoft.AspNetCore.Razor.TagHelpers;
using System;
namespace AdvancedApp.TagHelpers
{
[HtmlTargetElement("currency")]
public class CurrencyTagHelper : TagHelper
{
public decimal Amount { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
try
{
output.TagName = "span";
output.Content.SetContent($"${Amount:N2}");
}
catch (Exception ex)
{
output.Content.SetContent($"Error: {ex.Message}");
}
}
}
}
Step 2: Create a View ComponentCreate ViewComponents/RecentProductsViewComponent.cs:
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace AdvancedApp.ViewComponents
{
public class RecentProductsViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(int count)
{
try
{
// Simulate database fetch
var products = new List<Product>
{
new Product { Id = 1, Name = "Laptop", Price = 999.99m },
new Product { Id = 2, Name = "Smartphone", Price = 499.99m }
};
return View(products.Take(count));
}
catch (Exception ex)
{
return Content($"Error: {ex.Message}");
}
}
}
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
}
Create Views/Shared/Components/RecentProducts/Default.cshtml:
@model IEnumerable<AdvancedApp.ViewComponents.Product>
<h3>Recent Products</h3>
<ul>
@foreach (var product in Model)
{
<li>@product.Name - <currency amount="@product.Price"></currency></li>
}
</ul>
Step 3: Register Tag HelpersUpdate Views/_ViewImports.cshtml:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, AdvancedApp
Step 4: Use in a ViewUpdate Views/Home/Index.cshtml:
<h1>Welcome</h1>
<currency amount="123.45"></currency>
@await Component.InvokeAsync("RecentProducts", new { count = 2 })
Step 5: Test the ApplicationRun the application and verify that prices are formatted and recent products are displayed.
Output:
Welcome
$123.45
Recent Products
- Laptop - $999.99
- Smartphone - $499.99
This example demonstrates a custom tag helper for currency formatting and a view component for recent products, with error handling.
Background Services with IHostedService
What is IHostedService?
IHostedService is an interface in ASP.NET Core for running long-running background tasks, such as scheduled jobs, queue processing, or monitoring services.
Key Features
Hosted Services: Run as part of the application lifecycle.
Asynchronous: Support async/await for non-blocking tasks.
Lifecycle Management: Start and stop with the application.
Pros, Cons, and Alternatives for Background Services
Pros
Decoupled: Run independently of HTTP requests.
Flexible: Support various task types (e.g., timers, queues).
Built-in: Integrated with ASP.NET Core hosting.
Cons
Resource Usage: Can consume server resources if not optimized.
Complexity: Requires careful error handling and lifecycle management.
Scaling: Needs additional infrastructure for distributed systems.
Alternatives
Hangfire: For scheduled and recurring jobs.
Quartz.NET: For advanced job scheduling.
Azure Functions: For serverless background tasks.
Hosted Workers: Use worker services for dedicated background processing.
Example: Implementing a Background Service
Let’s create a background service to log server status periodically.
Step 1: Create a Background ServiceCreate Services/ServerStatusService.cs:
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AdvancedApp.Services
{
public class ServerStatusService : BackgroundService
{
private readonly ILogger<ServerStatusService> _logger;
public ServerStatusService(ILogger<ServerStatusService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
_logger.LogInformation($"Server status check at {DateTime.Now}");
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ServerStatusService");
}
}
}
}
}
Step 2: Register the ServiceUpdate Program.cs:
using AdvancedApp.Filters;
using AdvancedApp.Middleware;
using AdvancedApp.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<CustomAuthorizationFilter>();
options.Filters.Add<LoggingActionFilter>();
options.Filters.Add<CustomExceptionFilter>();
});
builder.Services.AddHostedService<ServerStatusService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRequestLogging();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Step 3: Test the ServiceRun the application and check logs for periodic server status messages.
Output (Logs):
info: AdvancedApp.Services.ServerStatusService[0]
Server status check at 8/20/2025 4:35:00 PM
This example demonstrates a background service for periodic tasks with error logging.
Localization & Globalization
Understanding Localization and Globalization
Globalization (G11N) prepares an application for multiple cultures, while Localization (L10N) adapts it to specific languages and regions.
Key Features
Resource Files: Store translations in .resx files.
Culture Settings: Use RequestLocalization middleware to set culture.
Format Support: Handle date, number, and currency formats per culture.
Pros, Cons, and Alternatives for Localization and Globalization
Pros
Global Reach: Supports multiple languages and regions.
Built-in: ASP.NET Core provides robust localization APIs.
Flexible: Supports resource files, databases, or external providers.
Cons
Complexity: Managing translations can be time-consuming.
Resource Overhead: Multiple resource files increase project size.
Testing: Requires testing for each supported culture.
Alternatives
Third-Party Services: Use services like Transifex or Crowdin for translations.
Client-Side Localization: Handle localization in JavaScript frameworks.
Static Content: Hardcode translations for small applications.
Example: Implementing Localization
Let’s add localization to support English and Spanish.
Step 1: Configure LocalizationUpdate Program.cs:
using AdvancedApp.Filters;
using AdvancedApp.Middleware;
using AdvancedApp.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Localization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<CustomAuthorizationFilter>();
options.Filters.Add<LoggingActionFilter>();
options.Filters.Add<CustomExceptionFilter>();
}).AddViewLocalization();
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddHostedService<ServerStatusService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRequestLogging();
app.UseRouting();
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("es-ES") },
SupportedUICultures = new[] { new CultureInfo("en-US"), new CultureInfo("es-ES") }
});
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Step 2: Create Resource FilesCreate Resources/Views/Home/Index.en-US.resx and Resources/Views/Home/Index.es-ES.resx.
Index.en-US.resx:
<data name="WelcomeMessage" xml:space="preserve">
<value>Welcome to the E-Commerce Dashboard</value>
</data>
Index.es-ES.resx:
<data name="WelcomeMessage" xml:space="preserve">
<value>Bienvenido al panel de comercio electrónico</value>
</data>
Step 3: Update Index.cshtml
@inject Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer Localizer
<h1>@Localizer["WelcomeMessage"]</h1>
<currency amount="123.45"></currency>
@await Component.InvokeAsync("RecentProducts", new { count = 2 })
Step 4: Test LocalizationRun the application and access / with query parameter ?culture=es-ES to see Spanish translations.
Output (Spanish):
Bienvenido al panel de comercio electrónico
$123.45
Recent Products
- Laptop - $999.99
- Smartphone - $499.99
This example demonstrates localization with resource files and culture switching.
Best Practices for Advanced ASP.NET Core Features
Security Best Practices
Middleware: Validate inputs and use HTTPS to secure data in transit.
Filters: Implement authorization filters to restrict access.
Tag Helpers/View Components: Sanitize outputs to prevent XSS.
Background Services: Restrict access to sensitive operations.
Localization: Avoid storing sensitive data in resource files.
Performance Best Practices
Middleware: Minimize processing in middleware to avoid pipeline delays.
Filters: Optimize filter logic to reduce overhead.
Tag Helpers/View Components: Cache output when possible.
Background Services: Use async/await and optimize resource usage.
Localization: Cache resource lookups for performance.
Error Handling Best Practices
Middleware: Log errors and return meaningful responses.
Filters: Use exception filters to handle errors gracefully.
Tag Helpers/View Components: Include fallback content for errors.
Background Services: Log and retry failed tasks.
Localization: Handle missing resources with default values.
Real-Life Example: Building an E-Commerce Dashboard
Let’s build an e-commerce dashboard that uses middleware for logging, filters for security, tag helpers and view components for UI, a background service for stock updates, and localization for multi-language support.
Step 1: Set Up the ProjectUse the existing project and add a product model and database.
Create Models/Product.cs:
namespace AdvancedApp.Models
{
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int Stock { get; set; }
}
}
Create Data/AppDbContext.cs:
using Microsoft.EntityFrameworkCore;
using AdvancedApp.Models;
namespace AdvancedApp.Data
{
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Product> Products { get; set; }
}
}
Step 2: Update Program.cs
using AdvancedApp.Data;
using AdvancedApp.Filters;
using AdvancedApp.Middleware;
using AdvancedApp.Services;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Localization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews(options =>
{
options.Filters.Add<CustomAuthorizationFilter>();
options.Filters.Add<LoggingActionFilter>();
options.Filters.Add<CustomExceptionFilter>();
}).AddViewLocalization();
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
builder.Services.AddHostedService<ServerStatusService>();
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRequestLogging();
app.UseRouting();
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-US"),
SupportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("es-ES") },
SupportedUICultures = new[] { new CultureInfo("en-US"), new CultureInfo("es-ES") }
});
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
Update appsettings.json:
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=AdvancedAppDb;Trusted_Connection=True;MultipleActiveResultSets=true"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Step 3: Update Background ServiceUpdate ServerStatusService.cs to update stock levels:
using AdvancedApp.Data;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Threading;
using System.Threading.Tasks;
namespace AdvancedApp.Services
{
public class ServerStatusService : BackgroundService
{
private readonly IServiceProvider _services;
private readonly ILogger<ServerStatusService> _logger;
public ServerStatusService(IServiceProvider services, ILogger<ServerStatusService> logger)
{
_services = services;
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
try
{
using (var scope = _services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
var products = context.Products;
foreach (var product in products)
{
product.Stock += new Random().Next(-5, 5);
if (product.Stock < 0) product.Stock = 0;
}
await context.SaveChangesAsync(stoppingToken);
_logger.LogInformation($"Stock updated at {DateTime.Now}");
}
await Task.Delay(TimeSpan.FromSeconds(30), stoppingToken);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error in ServerStatusService");
}
}
}
}
}
Step 4: Update HomeController.cs
using AdvancedApp.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Threading.Tasks;
namespace AdvancedApp.Controllers
{
public class HomeController : Controller
{
private readonly AppDbContext _context;
public HomeController(AppDbContext context)
{
_context = context;
}
public async Task<IActionResult> Index()
{
var products = await _context.Products.ToListAsync();
return View(products);
}
}
}
Step 5: Update Index.cshtml
@model IEnumerable<AdvancedApp.Models.Product>
@inject Microsoft.AspNetCore.Mvc.Localization.IViewLocalizer Localizer
<h1>@Localizer["WelcomeMessage"]</h1>
@await Component.InvokeAsync("RecentProducts", new { count = 2 })
<h3>Products</h3>
<ul>
@foreach (var product in Model)
{
<li>@product.Name - <currency amount="@product.Price"></currency> (Stock: @product.Stock)</li>
}
</ul>
Step 6: Create Migrations
dotnet ef migrations add InitialCreate
dotnet ef database update
Step 7: Seed DataAdd to Program.cs:
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<AppDbContext>();
context.Products.AddRange(
new Models.Product { Name = "Laptop", Price = 999.99m, Stock = 10 },
new Models.Product { Name = "Smartphone", Price = 499.99m, Stock = 20 }
);
await context.SaveChangesAsync();
}
Step 8: Test the ApplicationRun the application and verify:
Middleware logs requests.
Filters handle unauthorized access and exceptions.
Tag helpers format prices.
View components display recent products.
Background service updates stock levels.
Localization switches between English and Spanish.
Real-Life Scenario: This e-commerce dashboard demonstrates:
Middleware: Logs requests and restricts IPs.
Filters: Ensures secure access and handles errors.
Tag Helpers/View Components: Displays formatted prices and product widgets.
Background Service: Updates stock levels asynchronously.
Localization: Supports multiple languages for global users.
Conclusion
In Module 10 of our ASP.NET Core Complete Course, we explored Advanced ASP.NET Core Features, covering:
Middleware Deep Dive: Customizing the request pipeline.
Filters in MVC: Managing action execution and exceptions.
Custom Tag Helpers & View Components: Enhancing UI reusability.
Background Services with IHostedService: Running long-running tasks.
Localization & Globalization: Supporting multi-language applications.
Through practical examples and a real-life e-commerce dashboard, you’ve learned how to leverage these features with best practices for security, performance, and error handling. In the next module, we’ll explore deployment, testing, and advanced optimization techniques. Stay tuned!
FAQs
Q1: What is middleware in ASP.NET Core?
Middleware is software that processes HTTP requests and responses in a pipeline, handling tasks like logging or authentication.
Q2: How do filters differ from middleware?
Filters are MVC-specific and run during action execution, while middleware operates at the request pipeline level.
Q3: When should I use tag helpers vs. view components?
Use tag helpers for simple HTML enhancements and view components for complex, reusable UI with server-side logic.
Q4: What are background services used for?
Background services handle long-running tasks like scheduled jobs or queue processing.
Q5: How do I support multiple languages in ASP.NET Core?
Use localization middleware and resource files to provide translations for different cultures.
No comments:
Post a Comment
Thanks for your valuable comment...........
Md. Mominul Islam