--- name: blazor-performance description: Blazor rendering optimization, virtualization, lazy loading, caching, and memory management allowed-tools: - Read - Write - Edit - Grep triggers: - blazor performance - blazor slow - rendering optimization - virtualize - lazy loading - blazor caching --- # Blazor Performance Optimization ## Rendering Optimization ### Use @key for list rendering ```razor @foreach (var item in Items) { } ``` ### Override ShouldRender ```csharp private bool _shouldRender = true; protected override bool ShouldRender() => _shouldRender; ``` ### Virtualize large lists ```razor @* With item provider for server-side paging *@ @code { private async ValueTask> LoadItems( ItemsProviderRequest request) { var result = await Service.GetPagedAsync(request.StartIndex, request.Count); return new ItemsProviderResult(result.Items, result.TotalCount); } } ``` ### Streaming SSR for slow data ```razor @attribute [StreamRendering] @if (_data is null) { } else { } ``` ## Caching Strategies ### Output Caching (API endpoints) ```csharp app.MapGet("/api/products", async (AppDbContext db) => await db.Products.AsNoTracking().ToListAsync()) .CacheOutput(policy => policy.Expire(TimeSpan.FromMinutes(5)).Tag("products")); ``` ### Distributed Cache (Redis) ```csharp public sealed class CachedProductService( IProductRepository repo, IDistributedCache cache) : IProductService { public async Task GetByIdAsync(int id, CancellationToken ct) { var cacheKey = $"product:{id}"; var cached = await cache.GetStringAsync(cacheKey, ct); if (cached is not null) return JsonSerializer.Deserialize(cached); var product = await repo.GetByIdAsync(id, ct); if (product is not null) { await cache.SetStringAsync(cacheKey, JsonSerializer.Serialize(product), new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) }, ct); } return product; } } ``` ### Memory Cache for component state ```csharp @inject IMemoryCache Cache @code { protected override async Task OnInitializedAsync() { _categories = await Cache.GetOrCreateAsync("categories", async entry => { entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1); return await CategoryService.GetAllAsync(); }); } } ``` ## WASM Size Optimization - Enable trimming: `true` - Enable AOT compilation: `true` - Use lazy assembly loading for rarely-used features - Minimize NuGet packages in WASM project ## SignalR Connection (Blazor Server) - Monitor circuit count with Aspire dashboard - Set reasonable circuit timeout: `CircuitOptions.DisconnectedCircuitRetentionPeriod` - Minimize state stored in circuit (use external state stores) - Use `@rendermode InteractiveAuto` for high-traffic pages to offload to WASM