# Migration Plan: Blazorise to MudBlazor in ABP Framework ## Executive Summary This document outlines a phased approach to **replace** Blazorise with MudBlazor as the UI component library in ABP Framework. The migration will be gradual, allowing users time to migrate their existing applications before Blazorise packages are deprecated and eventually removed. **Key Strategy:** No abstraction layer - MudBlazor packages will directly replace Blazorise packages over time. --- ## Current Architecture Analysis ### Existing Blazorise Integration The ABP Framework currently uses Blazorise (v1.8.8) with the following structure: **Core Packages:** - `Volo.Abp.BlazoriseUI` - Core UI module with service implementations - `Volo.Abp.AspNetCore.Components.Web.Theming` - Theming infrastructure (currently depends on BlazoriseUI - **this needs to change**) **Hosting-Specific Packages:** - `Volo.Abp.AspNetCore.Components.Server.Theming` - `Volo.Abp.AspNetCore.Components.WebAssembly.Theming` - `Volo.Abp.AspNetCore.Components.MauiBlazor.Theming` **Feature Module Packages (using Blazorise components):** - `Volo.Abp.Identity.Blazor` - `Volo.Abp.TenantManagement.Blazor` - `Volo.Abp.PermissionManagement.Blazor` - `Volo.Abp.FeatureManagement.Blazor` - `Volo.Abp.SettingManagement.Blazor` - `Volo.Abp.Account.Blazor` ### Existing Service Abstractions ABP already has UI-agnostic service interfaces in `Volo.Abp.AspNetCore.Components`: - `IUiMessageService` - Message dialogs (Info, Success, Warn, Error, Confirm) - `IUiNotificationService` - Toast notifications - `IUiPageProgressService` - Page progress indicators These interfaces will be reused - only the implementations change from Blazorise to MudBlazor. ### Current Problem: Theming Package Dependency The `Volo.Abp.AspNetCore.Components.Web.Theming` package currently depends on `Volo.Abp.BlazoriseUI`, but analysis shows this dependency is **not necessary**. The theming package uses: 1. `BreadcrumbItem` class - A simple POCO that should be UI-agnostic 2. `PageHeader.razor` - Uses Blazorise components directly (should be moved) 3. `PageToolbarExtensions.AddButton` - Uses Blazorise `ToolbarButton` (should be moved) **Solution:** Refactor theming into UI-agnostic base + UI-specific implementations. --- ## Migration Timeline Overview | Phase | Description | Blazorise Status | |-------|-------------|------------------| | Phase 0 | Refactor theming architecture | Fully supported | | Phase 1 | Create MudBlazor core packages | Fully supported | | Phase 2 | Create MudBlazor theming | Fully supported | | Phase 3 | Create MudBlazor CRUD components | Fully supported | | Phase 4 | Create MudBlazor feature modules | Fully supported | | Phase 5 | Create MudBlazor themes | Fully supported | | Phase 6 | Update templates (MudBlazor default) | **Deprecated** | | Phase 7 | Documentation & migration guides | **Deprecated** | | Phase 8 | Remove Blazorise packages | **Removed** | --- ## Phase 0: Refactor Theming Architecture (Pre-requisite) **Objective:** Make `Volo.Abp.AspNetCore.Components.Web.Theming` UI-agnostic by removing its dependency on `Volo.Abp.BlazoriseUI`. ### 0.1 Move UI-Agnostic Classes Move `BreadcrumbItem` from `Volo.Abp.BlazoriseUI` to `Volo.Abp.AspNetCore.Components.Web`: ``` framework/src/Volo.Abp.AspNetCore.Components.Web/ └── Volo/Abp/AspNetCore/Components/Web/ └── Theming/ └── BreadcrumbItem.cs # Moved from BlazoriseUI ``` **BreadcrumbItem.cs** (UI-agnostic): ```csharp namespace Volo.Abp.AspNetCore.Components.Web.Theming; public class BreadcrumbItem { public string Text { get; set; } public object? Icon { get; set; } public string? Url { get; set; } public BreadcrumbItem(string text, string? url = null, object? icon = null) { Text = text; Url = url; Icon = icon; } } ``` ### 0.2 Refactor Theming Package Structure Split the theming infrastructure: ``` BEFORE (Current): ───────────────── Volo.Abp.AspNetCore.Components.Web.Theming ├── Depends on: Volo.Abp.BlazoriseUI ❌ (Problem!) ├── PageHeader.razor (Blazorise components) ├── PageToolbarExtensions.cs (uses ToolbarButton) └── Theming infrastructure (UI-agnostic) AFTER (Refactored): ─────────────────── Volo.Abp.AspNetCore.Components.Web.Theming (UI-Agnostic) ├── Depends on: Volo.Abp.AspNetCore.Components.Web ✓ ├── Depends on: Volo.Abp.UI.Navigation ✓ ├── NO dependency on BlazoriseUI or MudBlazorUI ✓ ├── Theming/ │ ├── ITheme.cs │ ├── IThemeManager.cs │ ├── IThemeSelector.cs │ ├── ThemeDictionary.cs │ └── ... ├── PageToolbars/ │ ├── IPageToolbarManager.cs │ ├── PageToolbar.cs │ ├── PageToolbarItem.cs │ └── ... (no UI-specific extensions) ├── Toolbars/ │ ├── IToolbarManager.cs │ ├── Toolbar.cs │ └── ... ├── Routing/ │ └── AbpRouterOptions.cs └── Layout/ ├── PageLayout.cs (uses BreadcrumbItem from Components.Web) └── StandardLayouts.cs Volo.Abp.AspNetCore.Components.Web.Theming.Blazorise (Blazorise-Specific) ├── Depends on: Volo.Abp.AspNetCore.Components.Web.Theming ✓ ├── Depends on: Volo.Abp.BlazoriseUI ✓ ├── AbpAspNetCoreComponentsWebThemingBlazoriseModule.cs ├── Components/ │ └── PageHeader.razor (Blazorise implementation) └── PageToolbars/ └── BlazorisePageToolbarExtensions.cs (AddButton with ToolbarButton) Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor (MudBlazor-Specific) ├── Depends on: Volo.Abp.AspNetCore.Components.Web.Theming ✓ ├── Depends on: Volo.Abp.MudBlazorUI ✓ ├── AbpAspNetCoreComponentsWebThemingMudBlazorModule.cs ├── Components/ │ └── PageHeader.razor (MudBlazor implementation) └── PageToolbars/ └── MudBlazorPageToolbarExtensions.cs (AddButton with MudButton) ``` ### 0.3 Updated Package Dependencies **`Volo.Abp.AspNetCore.Components.Web.Theming.csproj`** (UI-Agnostic): ```xml net10.0 ``` **`Volo.Abp.AspNetCore.Components.Web.Theming.Blazorise.csproj`**: ```xml net10.0 ``` **`Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.csproj`**: ```xml net10.0 ``` ### 0.4 Module Updates **`AbpAspNetCoreComponentsWebThemingModule.cs`** (UI-Agnostic): ```csharp using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.Modularity; using Volo.Abp.UI.Navigation; namespace Volo.Abp.AspNetCore.Components.Web.Theming; [DependsOn( typeof(AbpAspNetCoreComponentsWebModule), // NOT BlazoriseUI! typeof(AbpUiNavigationModule) )] public class AbpAspNetCoreComponentsWebThemingModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { Configure(options => { options.Components.Add(typeof(AbpAuthenticationState), null); }); } } ``` **`AbpAspNetCoreComponentsWebThemingBlazoriseModule.cs`**: ```csharp using Volo.Abp.BlazoriseUI; using Volo.Abp.Modularity; namespace Volo.Abp.AspNetCore.Components.Web.Theming.Blazorise; [DependsOn( typeof(AbpAspNetCoreComponentsWebThemingModule), typeof(AbpBlazoriseUIModule) )] public class AbpAspNetCoreComponentsWebThemingBlazoriseModule : AbpModule { } ``` **`AbpAspNetCoreComponentsWebThemingMudBlazorModule.cs`**: ```csharp using Volo.Abp.MudBlazorUI; using Volo.Abp.Modularity; namespace Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor; [DependsOn( typeof(AbpAspNetCoreComponentsWebThemingModule), typeof(AbpMudBlazorUIModule) )] public class AbpAspNetCoreComponentsWebThemingMudBlazorModule : AbpModule { } ``` ### 0.5 Hosting-Specific Theming Packages Apply the same pattern to hosting-specific packages: ``` BEFORE: ├── Volo.Abp.AspNetCore.Components.Server.Theming (depends on Blazorise.Bootstrap5) ├── Volo.Abp.AspNetCore.Components.WebAssembly.Theming (depends on Blazorise.Bootstrap5) └── Volo.Abp.AspNetCore.Components.MauiBlazor.Theming (depends on Blazorise.Bootstrap5) AFTER: ├── Volo.Abp.AspNetCore.Components.Server.Theming (UI-agnostic base) ├── Volo.Abp.AspNetCore.Components.Server.Theming.Blazorise (Blazorise-specific) ├── Volo.Abp.AspNetCore.Components.Server.Theming.MudBlazor (MudBlazor-specific) │ ├── Volo.Abp.AspNetCore.Components.WebAssembly.Theming (UI-agnostic base) ├── Volo.Abp.AspNetCore.Components.WebAssembly.Theming.Blazorise (Blazorise-specific) ├── Volo.Abp.AspNetCore.Components.WebAssembly.Theming.MudBlazor (MudBlazor-specific) │ ├── Volo.Abp.AspNetCore.Components.MauiBlazor.Theming (UI-agnostic base) ├── Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.Blazorise (Blazorise-specific) └── Volo.Abp.AspNetCore.Components.MauiBlazor.Theming.MudBlazor (MudBlazor-specific) ``` --- ## Phase 1: MudBlazor Core Package **Objective:** Create the core MudBlazor UI package that implements ABP's UI service interfaces. ### 1.1 Create `Volo.Abp.MudBlazorUI` ``` framework/src/Volo.Abp.MudBlazorUI/ ├── Volo.Abp.MudBlazorUI.csproj ├── AbpMudBlazorUIModule.cs ├── MudBlazorUiMessageService.cs ├── MudBlazorUiNotificationService.cs ├── MudBlazorUiPageProgressService.cs ├── AbpMudCrudPageBase.cs ├── Components/ │ ├── AbpMudExtensibleDataGrid.razor │ ├── AbpMudExtensibleDataGrid.razor.cs │ ├── MudDataGridEntityActionsColumn.razor │ ├── MudEntityAction.razor │ ├── MudEntityActions.razor │ ├── UiMessageAlert.razor │ ├── UiNotificationAlert.razor │ ├── UiPageProgress.razor │ ├── MudSubmitButton.razor │ ├── MudToolbarButton.razor │ ├── MudPageAlert.razor │ └── ObjectExtending/ │ ├── MudExtensionProperties.razor │ ├── MudTextExtensionProperty.razor │ ├── MudTextAreaExtensionProperty.razor │ ├── MudCheckExtensionProperty.razor │ ├── MudSelectExtensionProperty.razor │ ├── MudDateTimeExtensionProperty.razor │ ├── MudTimeExtensionProperty.razor │ └── MudLookupExtensionProperty.razor ├── MudBlazorUiObjectExtensionPropertyInfoExtensions.cs ├── MudBlazorExtensionPropertyPolicyChecker.cs └── wwwroot/ └── volo.abp.mudblazorui.css ``` ### 1.2 Project File: `Volo.Abp.MudBlazorUI.csproj` ```xml net10.0 ``` ### 1.3 Module Class: `AbpMudBlazorUIModule.cs` ```csharp using Microsoft.Extensions.DependencyInjection; using MudBlazor.Services; using Volo.Abp.AspNetCore.Components.Web; using Volo.Abp.Authorization; using Volo.Abp.Ddd.Application.Contracts; using Volo.Abp.Features; using Volo.Abp.GlobalFeatures; using Volo.Abp.Modularity; namespace Volo.Abp.MudBlazorUI; [DependsOn( typeof(AbpAspNetCoreComponentsWebModule), typeof(AbpDddApplicationContractsModule), typeof(AbpAuthorizationModule), typeof(AbpGlobalFeaturesModule), typeof(AbpFeaturesModule) )] public class AbpMudBlazorUIModule : AbpModule { public override void ConfigureServices(ServiceConfigurationContext context) { context.Services.AddMudServices(config => { config.SnackbarConfiguration.PositionClass = Defaults.Classes.Position.BottomRight; config.SnackbarConfiguration.PreventDuplicates = false; config.SnackbarConfiguration.NewestOnTop = true; config.SnackbarConfiguration.ShowCloseIcon = true; config.SnackbarConfiguration.VisibleStateDuration = 5000; }); } } ``` ### 1.4 Component Mapping (Blazorise → MudBlazor) | Blazorise Component | MudBlazor Equivalent | Notes | |---------------------|----------------------|-------| | `` | `` | Different API for columns | | `` | `` | Uses `IDialogService` | | `