Blazor Server vs Blazor WebAssembly

Découvrez les concepts essentiels de Blazor Server vs Blazor WebAssembly avec des exemples pratiques et des bonnes pratiques.

Olivier Dupuy
21 juillet 2025

10

Vues

0

Commentaires

2

Min de lecture

Optimisation des performances

Les performances sont cruciales dans les applications modernes. Cet article explore Blazor Server vs Blazor WebAssembly et les techniques d'optimisation essentielles pour maximiser les performances de vos applications .NET.

Métriques et monitoring

Avant d'optimiser, il faut mesurer :

  • Temps de réponse des API
  • Utilisation mémoire et CPU
  • Throughput et latence
  • Allocation d'objets et Garbage Collection

Techniques d'optimisation

1. Mise en cache intelligente

// Configuration du cache mémoire
builder.Services.AddMemoryCache();
builder.Services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost";
});

// Service avec cache
public class CachedDataService
{
    private readonly IMemoryCache _cache;
    private readonly IDataRepository _repository;
    
    public CachedDataService(IMemoryCache cache, IDataRepository repository)
    {
        _cache = cache;
        _repository = repository;
    }
    
    public async Task<List<DataModel>> GetDataAsync(int categoryId)
    {
        var cacheKey = $"data_category_{categoryId}";
        
        if (_cache.TryGetValue(cacheKey, out List<DataModel> cachedData))
        {
            return cachedData;
        }
        
        var data = await _repository.GetByCategoryAsync(categoryId);
        
        var cacheOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(15),
            SlidingExpiration = TimeSpan.FromMinutes(5),
            Priority = CacheItemPriority.High
        };
        
        _cache.Set(cacheKey, data, cacheOptions);
        return data;
    }
}

2. Optimisation des requêtes Entity Framework

// Requêtes optimisées avec projections
public class OptimizedRepository
{
    private readonly ApplicationDbContext _context;
    
    public OptimizedRepository(ApplicationDbContext context)
    {
        _context = context;
    }
    
    // Mauvais : charge toute l'entité
    public async Task<List<Article>> GetArticlesBad()
    {
        return await _context.Articles
            .Include(a => a.Category)
            .Include(a => a.Author)
            .ToListAsync();
    }
    
    // Bon : projection avec seulement les données nécessaires
    public async Task<List<ArticleDto>> GetArticlesOptimized()
    {
        return await _context.Articles
            .Select(a => new ArticleDto
            {
                Id = a.Id,
                Title = a.Title,
                Summary = a.Summary,
                CategoryName = a.Category.Name,
                AuthorName = a.Author.FirstName + " " + a.Author.LastName,
                PublishedAt = a.PublishedAt
            })
            .AsNoTracking() // Pas de tracking pour les lectures seules
            .ToListAsync();
    }
    
    // Pagination efficace
    public async Task<PagedResult<ArticleDto>> GetPagedArticlesAsync(int page, int pageSize)
    {
        var totalCount = await _context.Articles.CountAsync();
        
        var articles = await _context.Articles
            .OrderByDescending(a => a.PublishedAt)
            .Skip((page - 1) * pageSize)
            .Take(pageSize)
            .Select(a => new ArticleDto { /* projection */ })
            .AsNoTracking()
            .ToListAsync();
            
        return new PagedResult<ArticleDto>(articles, totalCount, page, pageSize);
    }
}

3. Optimisation des allocations mémoire

// Utilisation de Span<T> et Memory<T> pour éviter les allocations
public class StringProcessor
{
    public string ProcessData(ReadOnlySpan<char> input)
    {
        // Traitement sans allocation inutile
        Span<char> buffer = stackalloc char[256];
        
        var processed = 0;
        foreach (var c in input)
        {
            if (char.IsLetter(c))
            {
                buffer[processed++] = char.ToUpper(c);
            }
        }
        
        return new string(buffer[..processed]);
    }
    
    // Pool d'objets pour réutiliser les instances
    private static readonly ObjectPool<StringBuilder> StringBuilderPool = 
        new DefaultObjectPoolProvider().CreateStringBuilderPool();
    
    public string BuildString(IEnumerable<string> parts)
    {
        var sb = StringBuilderPool.Get();
        try
        {
            foreach (var part in parts)
            {
                sb.Append(part);
                sb.Append("|");
            }
            return sb.ToString();
        }
        finally
        {
            StringBuilderPool.Return(sb);
        }
    }
}

Monitoring avec Application Insights

// Configuration du monitoring
builder.Services.AddApplicationInsightsTelemetry();

// Custom metrics
public class PerformanceMetrics
{
    private readonly TelemetryClient _telemetryClient;
    
    public PerformanceMetrics(TelemetryClient telemetryClient)
    {
        _telemetryClient = telemetryClient;
    }
    
    public void TrackProcessingTime(string operation, double duration)
    {
        _telemetryClient.TrackMetric($"ProcessingTime_{operation}", duration);
    }
    
    public void TrackCacheHit(string cacheKey)
    {
        _telemetryClient.TrackEvent("CacheHit", new Dictionary<string, string>
        {
            { "CacheKey", cacheKey }
        });
    }
}

Benchmarking avec BenchmarkDotNet

[MemoryDiagnoser]
[SimpleJob(RuntimeMoniker.Net80)]
public class PerformanceBenchmark
{
    private readonly List<string> _data = Enumerable.Range(0, 1000)
        .Select(i => $"Item {i}").ToList();
    
    [Benchmark]
    public string ConcatenateWithStringBuilder()
    {
        var sb = new StringBuilder();
        foreach (var item in _data)
        {
            sb.Append(item);
        }
        return sb.ToString();
    }
    
    [Benchmark]
    public string ConcatenateWithJoin()
    {
        return string.Join("", _data);
    }
}

Conclusion

L'optimisation des performances avec Blazor Server vs Blazor WebAssembly nécessite une approche méthodique. Mesurez d'abord, optimisez ensuite, et validez les résultats. Les techniques présentées - mise en cache, optimisation des requêtes, gestion mémoire et monitoring - forment la base d'applications performantes et scalables.

Partager cet article
42
12

Commentaires (0)

Rejoignez la discussion

Connectez-vous pour partager votre avis et échanger avec la communauté

Première discussion

Soyez le premier à partager votre avis sur cet article !

À propos de l'auteur
Olivier Dupuy

Développeur passionné et créateur de contenu technique. Expert en développement web moderne avec ASP.NET Core, JavaScript, et technologies cloud.

Profil
Articles similaires
API versioning strategies
02 août 2025 0
C# & .NET
Cryptographie post-quantique
02 août 2025 0
C# & .NET
Géolocalisation et cartes interactives
02 août 2025 0
C# & .NET
Navigation rapide
Commentaires (0)