Exercise: ASP.NET Core Blazor Logging
Exercise Set 3: ASP.NET Core Blazor Logging
Goal: Understand how to add logging to Blazor components and services, and how to configure logging levels.
Scenario: Add logging to the "Product Catalog" application to track component initialization, product viewing, and any potential issues.
Instructions:
Part 1: Basic Logging in Components and Service
Continue from Exercise Set 2. If you closed it, open BlazorRoutingExercise.
1. Configure Logging in Program.cs:
- Open
Program.cs. - Add
using Microsoft.Extensions.Logging;at the top. - Add the following configuration within the
var builder = WebApplication.CreateBuilder(args);block (beforevar app = builder.Build();):
Program.cs (additions/modifications):
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; using BlazorRoutingExercise.Data; // Ensure this using is present for ProductDataService namespace using Microsoft.Extensions.Logging; // Add this using statement for logging configuration var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton<WeatherForecastService>(); // Default Blazor service builder.Services.AddSingleton<IProductDataService, ProductDataService>(); // From Exercise 2 // Configure Logging Providers and Filters: // Analogy: Setting up our security cameras and deciding what they should record. builder.Logging.ClearProviders(); // Clear default console provider builder.Logging.AddConsole(); // Send logs to the console window where the server runs builder.Logging.AddDebug(); // Send logs to the Debug output window in Visual Studio // Set minimum log levels for different categories (namespaces). // If a category isn't listed, it inherits from its parent or the Default. builder.Logging.SetMinimumLevel(LogLevel.Information); // Default to Information and higher // Log our specific application components/services at Debug or Information level builder.Logging.AddFilter("BlazorRoutingExercise.Data.ProductDataService", LogLevel.Debug); builder.Logging.AddFilter("BlazorRoutingExercise.Pages.ProductList", LogLevel.Information); builder.AddFilter("BlazorRoutingExercise.Pages.ProductDetails", LogLevel.Information); // Reduce noise from Microsoft/System framework logs builder.Logging.AddFilter("Microsoft", LogLevel.Warning); builder.Logging.AddFilter("System", LogLevel.Warning); app = builder.Build(); // ... (rest of Program.cs remains unchanged) ...
2. Add ILogger to ProductDataService:
- Open
Data/ProductDataService.cs. - Add
using Microsoft.Extensions.Logging;at the top. - Modify the constructor to accept
ILogger<ProductDataService>:
Data/ProductDataService.cs (modified constructor):
using Microsoft.Extensions.Logging; // Add this // ... other usings ... namespace BlazorRoutingExercise.Data { public class ProductDataService : IProductDataService { private List<Product> _products = new List<Product> { /* ... products ... */ }; private readonly ILogger<ProductDataService> _logger; // Declare logger // Inject the logger via constructor public ProductDataService(ILogger<ProductDataService> logger) { _logger = logger; _logger.LogInformation("ProductDataService initialized with {ProductCount} products.", _products.Count); } // ... (rest of class remains unchanged) ... } }
- Add a log statement to
GetProductById:
Data/ProductDataService.cs (modified GetProductById):
public Product? GetProductById(int id) { _logger.LogDebug("Attempting to retrieve product with ID: {ProductId}", id); var product = _products.FirstOrDefault(p => p.Id == id); if (product == null) { _logger.LogWarning("Product with ID {ProductId} not found.", id); } return product; }
Important: If ProductDataService was registered as a Singleton in Program.cs in the previous exercise, you're all set. If it was AddScoped or AddTransient, the DI container will still correctly provide the ILogger.
3. Add ILogger to ProductList.razor:
- Open
Pages/ProductList.razor. - Add
@inject ILogger<ProductList> Loggerat the top. - Add log statements:
Pages/ProductList.razor (relevant section):
@page "/products" @using BlazorRoutingExercise.Data @using BlazorRoutingExercise.Models @inject NavigationManager NavManager @inject IProductDataService ProductService // From Exercise 2 @inject ILogger<ProductList> Logger // Add this line @* ... HTML markup ... *@ @code { // ... existing code ... protected override void OnInitialized() { products = ProductService.GetAllProducts(); Logger.LogInformation("ProductList component initialized. Displaying {ProductCount} products.", products.Count); } private void ViewProductDetails(int productId) { Logger.LogInformation("Navigating to details for Product ID: {ProductId}", productId); NavManager.NavigateTo($"productdetails/{productId}"); } }
4. Add ILogger to ProductDetails.razor:
- Open
Pages/ProductDetails.razor. - Add
@inject ILogger<ProductDetails> Loggerat the top. - Add log statements:
Pages/ProductDetails.razor (relevant section):
@page "/productdetails/{ProductId:int}" @using BlazorRoutingExercise.Data @using BlazorRoutingExercise.Models @inject NavigationManager NavManager @inject IProductDataService ProductService // From Exercise 2 @inject ILogger<ProductDetails> Logger // Add this line @* ... HTML markup ... *@ @code { [Parameter] public int ProductId { get; set; } // private ProductDataService _productService = new ProductDataService(); // Removed from Exercise 2 private Product? product; protected override void OnParametersSet() { Logger.LogInformation("ProductDetails component parameters set. Looking for Product ID: {ProductId}", ProductId); product = ProductService.GetProductById(ProductId); if (product == null) { Logger.LogError("Product with ID {ProductId} was requested but not found in data service.", ProductId); } } private void GoBack() { Logger.LogInformation("Navigating back to product list."); NavManager.NavigateTo("/products"); } }
5. Test Your Logging:
- Run the application.
- Open Visual Studio's Output window (
View > Output, then select "Web Server" or "ASP.NET Core Web Server" from the dropdown). - Navigate through the "Products" page and click "View Details" for a few products.
- Observe:
- You should see Information logs for component initialization and navigation actions.
- You should see Debug logs from
ProductDataService.GetProductById(because we set its filter toLogLevel.Debug). - If you manually type an invalid product ID in the URL (e.g.,
/productdetails/999), you should see Warning logs fromProductDataServiceand Error logs fromProductDetails.razor.
Part 2: Challenge - Log Levels and Custom Messages
1. Experiment with Log Levels:
- In
Program.cs, change the filter forBlazorRoutingExercise.Pages.ProductDetailsfromLogLevel.InformationtoLogLevel.Debug. - Run the app. Does it generate more logs when you navigate to product details? (Yes, if you added Debug logs to that component).
- Change the filter for
BlazorRoutingExercise.Data.ProductDataServicefromLogLevel.DebugtoLogLevel.Warning. - Run the app. Do you still see the
LogDebugmessages fromGetProductById? (No, because the filter now only allows Warning and higher). - Change it back to
LogLevel.Debugfor the next steps.
Program.cs (filter change example):
// ... other filters ... builder.Logging.AddFilter("BlazorRoutingExercise.Pages.ProductDetails", LogLevel.Debug); // ...
Program.cs (filter change example):
// ... other filters ... builder.Logging.AddFilter("BlazorRoutingExercise.Data.ProductDataService", LogLevel.Warning); // ...
2. Challenge:
- In
ProductList.razor, add a customLogDebugmessage inside the@foreachloop, perhaps logging the name of each product as it's being rendered. - Verify that this log only appears when
LogLevel.Debugis configured forProductList.razorinProgram.cs.
Pages/ProductList.razor (Challenge modification):
@* ... existing HTML and @code block ... *@ @code { // ... existing code ... protected override void OnInitialized() { products = ProductService.GetAllProducts(); Logger.LogInformation("ProductList component initialized. Displaying {ProductCount} products.", products.Count); // Challenge: Add a LogDebug message for each product being rendered foreach (var product in products) { Logger.LogDebug("Rendering product: {ProductName} (ID: {ProductId})", product.Name, product.Id); } } // ... rest of code ... }
This tutorial guide clearly shows how to integrate and utilize the powerful logging capabilities in Blazor applications for monitoring and debugging.
Comments
Post a Comment