BLAZMVVM0013: MvvmOwningComponentBase Usage Analyzer
Diagnostic Information
- Diagnostic ID: BLAZMVVM0013
- Category: Blazing.Mvvm
- Severity: Warning
- Title: Component should use MvvmOwningComponentBase for scoped services
Description
This analyzer detects when a Blazor component uses MvvmComponentBase<TViewModel> but the ViewModel depends on scoped services (such as Entity Framework DbContext). In such cases, the component should inherit from MvvmOwningComponentBase<TViewModel> instead to create a service scope and ensure proper lifetime management of scoped dependencies.
Problem
When a ViewModel injects scoped services like DbContext, using the standard MvvmComponentBase can lead to:
- Shared DbContext instances across multiple components
- Connection leaks and resource exhaustion
- Thread safety issues with concurrent database operations
- Stale data due to long-lived contexts
Solution
Use MvvmOwningComponentBase<TViewModel> which creates a dedicated service scope for the component and its ViewModel, ensuring:
- Each component instance gets its own scoped service instances
- Proper disposal of scoped services when the component is disposed
- Thread-safe database operations
- Fresh data for each component render
Examples
❌ Incorrect (Using MvvmComponentBase with scoped services)
// ViewModel with DbContext dependency
public class ProductsViewModel : ViewModelBase
{
private readonly MyDbContext _context;
public ProductsViewModel(MyDbContext context) // Scoped service
{
_context = context;
}
public async Task<List<Product>> GetProductsAsync()
{
return await _context.Products.ToListAsync();
}
}
// View - INCORRECT: Should use MvvmOwningComponentBase
@page "/products"
@inherits MvvmComponentBase<ProductsViewModel> // ⚠️ Warning BLAZMVVM0013
<h3>Products</h3>
✅ Correct (Using MvvmOwningComponentBase)
// ViewModel with DbContext dependency
public class ProductsViewModel : ViewModelBase
{
private readonly MyDbContext _context;
public ProductsViewModel(MyDbContext context)
{
_context = context;
}
public async Task<List<Product>> GetProductsAsync()
{
return await _context.Products.ToListAsync();
}
}
// View - CORRECT: Uses MvvmOwningComponentBase
@page "/products"
@inherits MvvmOwningComponentBase<ProductsViewModel> // ✅ Correct
<h3>Products</h3>
Common Scoped Services
The analyzer detects these common scoped service patterns:
- Entity Framework Core:
DbContext,Database,DbConnection - Database connections:
IDbConnection,SqlConnection,MySqlConnection - Unit of Work pattern: Interfaces/classes containing "UnitOfWork", "Repository"
- Custom scoped services: Services registered with
ServiceLifetime.Scoped
When to Use Each Base Class
| Scenario | Base Class | Reason |
|---|---|---|
| ViewModel uses only transient/singleton services | MvvmComponentBase |
No service scope needed |
ViewModel injects DbContext or database connections |
MvvmOwningComponentBase |
Creates owned scope for proper disposal |
| ViewModel uses scoped services | MvvmOwningComponentBase |
Ensures proper service lifetime |
| No ViewModel | ComponentBase |
Standard Blazor component |
Service Registration Example
// Program.cs or Startup.cs
builder.Services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(connectionString)); // Registered as SCOPED by default
// ViewModels
builder.Services.AddBlazingMvvm(options =>
{
options.HostAssembly = typeof(Program).Assembly;
});
Benefits of MvvmOwningComponentBase
- Automatic scope management: Creates and disposes service scope automatically
- Thread safety: Each component gets its own DbContext instance
- Memory management: Scoped services are disposed when component is disposed
- Best practice compliance: Follows Microsoft's recommendations for scoped services in Blazor
Additional Resources
Related Analyzers
- BLAZMVVM0003: MvvmComponentBase Usage Analyzer
- BLAZMVVM0015: Dispose Pattern Analyzer
- BLAZMVVM0009: Service Injection Analyzer