<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel xmlns:media="http://search.yahoo.com/mrss/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <title>ABP.IO Stories</title>
    <link>https://abp.io/community/articles</link>
    <description>A hub for ABP Framework, .NET, and software development. Access articles, tutorials, news, and contribute to the ABP community.</description>
    <lastBuildDate>Sun, 08 Mar 2026 12:59:47 Z</lastBuildDate>
    <generator>Community - ABP.IO</generator>
    <image>
      <url>https://abp.io/assets/favicon.ico/favicon-32x32.png</url>
      <title>ABP.IO Stories</title>
      <link>https://abp.io/community/articles</link>
    </image>
    <a10:link rel="self" type="application/rss+xml" title="self" href="https://abp.io/community/rss?member=a-urel" />
    <item>
      <guid isPermaLink="true">https://abp.io/community/videos/customize-abp-blazor-application-ui-with-mudblazor-wscmpu3w</guid>
      <link>https://abp.io/community/videos/customize-abp-blazor-application-ui-with-mudblazor-wscmpu3w</link>
      <a10:author>
        <a10:name>a-urel</a10:name>
        <a10:uri>https://abp.io/community/members/a-urel</a10:uri>
      </a10:author>
      <category>customization</category>
      <category>blazor</category>
      <category>MudBlazor</category>
      <title>Customize ABP Blazor Application UI with MudBlazor</title>
      <description>In this video, you'll learn how to customize your ABP Blazor application's UI with MudBlazor components.</description>
      <pubDate>Tue, 05 Apr 2022 00:54:06 Z</pubDate>
      <a10:updated>2026-03-04T05:47:54Z</a10:updated>
      <content:encoded><![CDATA[In this video, you'll learn how to customize your ABP Blazor application's UI with MudBlazor components. <br \> <a href="https://www.youtube.com/watch?v=7f_GssoKl3A&ab_channel=AhmetUrel" rel="nofollow noopener noreferrer" title="Go to the Video">Go to the Video</a>]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/888e1032-d99e-2adc-178d-3a030963c766" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/888e1032-d99e-2adc-178d-3a030963c766" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-final-3dszry6c</guid>
      <link>https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-final-3dszry6c</link>
      <a10:author>
        <a10:name>a-urel</a10:name>
        <a10:uri>https://abp.io/community/members/a-urel</a10:uri>
      </a10:author>
      <category>blazor-wasm</category>
      <category>MudBlazor</category>
      <title>MudBlazor Theme in ABP Blazor WebAssembly (FINAL)</title>
      <description>In this part, I will show you how to customize/override pre-built Blazor pages of the Identity Module using MudBlazor components.</description>
      <pubDate>Wed, 30 Mar 2022 02:21:24 Z</pubDate>
      <a10:updated>2026-03-08T05:58:47Z</a10:updated>
      <content:encoded><![CDATA[<h1>MudBlazor Theme in ABP Blazor WebAssembly FINAL</h1>
<h2>Introduction</h2>
<p>In this part, I will show you how to customize/override pre-built Blazor pages of the <a href="https://docs.abp.io/en/abp/latest/Modules/Identity">Identity Module</a> using <a href="https://www.mudblazor.com/">MudBlazor</a> components. I assume that Tenant and Setting management pages are rarely used by end-users, so these modules are not covered in this sample to keep it short. You can customize every page using the principles shown here. All you need to do is:</p>
<ol>
<li>Deriving a class that inherits the class you want to override</li>
<li>And adding the following attributes to the derived class:</li>
</ol>
<pre><code class="language-razor">@* to the razor file *@
@attribute [ExposeServices(typeof(BASE-CLASS))]
@attribute [Dependency(ReplaceServices = true)]
</code></pre>
<pre><code class="language-charp">// or to the C# file
[ExposeServices(typeof(BASE-CLASS))]
[Dependency(ReplaceServices = true)]
</code></pre>
<p>See <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Customization-Overriding-Components">Blazor UI: Customization / Overriding Components</a> for more information.</p>
<h2>16. Make Sure You Have Completed Previous Parts</h2>
<p>You must complete the steps in <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor">Part 1</a>, <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor2">Part 2</a>, <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor3">Part 3</a>, and <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor4">Part 4</a> to continue.</p>
<h2>17. Create Required Files</h2>
<p>Create <code>Identity</code> folder under <code>Acme.BookStore.Blazor/Pages/</code>.</p>
<p>Create the following files in this folder:</p>
<ol>
<li><code>MudPermissionManagementModal.razor</code></li>
<li><code>MudPermissionManagementModal.razor.cs</code></li>
<li><code>MudRoleManagement.razor</code></li>
<li><code>MudRoleManagement.razor.cs</code></li>
<li><code>MudUserManagement.razor</code></li>
<li><code>MudUserManagement.razor.cs</code></li>
</ol>
<h2>18. Modify These Files' Content As Shown Below</h2>
<ol>
<li><code>MudPermissionManagementModal.razor</code></li>
</ol>
<pre><code class="language-razor">@using Microsoft.Extensions.Localization
@using Volo.Abp.PermissionManagement.Blazor.Components
@using Volo.Abp.PermissionManagement.Localization
@inherits PermissionManagementModal

&lt;MudDialog @bind-IsVisible=&quot;_isVisible&quot;
           Options=&quot;DialogOptions&quot;&gt;
    &lt;TitleContent&gt;
        &lt;MudText Typo=&quot;Typo.h6&quot;&gt;                    
            @L[&quot;Permissions&quot;] - @_entityDisplayName
        &lt;/MudText&gt;
    &lt;/TitleContent&gt;
    &lt;DialogContent&gt;
        &lt;MudContainer&gt;
            &lt;MudCheckBox T=&quot;bool&quot; @bind-Checked=&quot;@GrantAll&quot;&gt;
                @L[&quot;SelectAllInAllTabs&quot;]
            &lt;/MudCheckBox&gt;
            &lt;MudDivider /&gt;
            @if (_groups != null)
            {
                &lt;MudTabs Position=&quot;MudBlazor.Position.Left&quot; &gt;
                    &lt;TabPanelHeader&gt;
                        &lt;MudText&gt;
                            @* ?! *@
                            &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
                        &lt;/MudText&gt;
                    &lt;/TabPanelHeader&gt;
                    &lt;ChildContent&gt;
                        @foreach (var group in _groups)
                        {
                            &lt;MudTabPanel BadgeColor=&quot;MudBlazor.Color.Secondary&quot;
                                         BadgeData=&quot;@(group.Permissions.Count(x =&gt; x.IsGranted))&quot;
                                         Text=&quot;@(group.DisplayName)&quot;&gt;
                                &lt;MudContainer Style=&quot;width: 400px; height: 400px; overflow-y: scroll&quot;&gt;
                                    &lt;MudGrid&gt;
                                        &lt;MudItem xs=&quot;12&quot;&gt;
                                            &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@group.DisplayName&lt;/MudText&gt;
                                            &lt;MudDivider /&gt;
                                        &lt;/MudItem&gt;
                                        &lt;MudItem xs=&quot;12&quot;&gt;
                                            &lt;MudCheckBox T=&quot;bool&quot;
                                                        Checked=&quot;@(group.Permissions.All(x =&gt; x.IsGranted))&quot;
                                                        CheckedChanged=&quot;@(b =&gt; GroupGrantAllChanged(b, group))&quot;&gt;
                                            @L[&quot;SelectAllInThisTab&quot;]
                                        &lt;/MudCheckBox&gt;
                                        &lt;MudDivider /&gt;
                                        &lt;/MudItem&gt;
                                        @foreach (var permission in group.Permissions)
                                        {
                                            &lt;MudItem xs=&quot;1&quot;&gt;
                                            &lt;/MudItem&gt;
                                            &lt;MudItem xs=&quot;11&quot;&gt;
                                                &lt;MudCheckBox T=&quot;bool&quot;
                                                                Style=&quot;padding-inline-start: 16px;&quot;
                                                                Disabled=&quot;@(IsDisabledPermission(permission))&quot;
                                                                Checked=&quot;@permission.IsGranted&quot;
                                                                CheckedChanged=&quot;@(b =&gt; PermissionChanged(b, group, permission))&quot;&gt;
                                                    @GetShownName(permission)
                                                &lt;/MudCheckBox&gt;
                                            &lt;/MudItem&gt;
                                        }
                                    &lt;/MudGrid&gt;
                                &lt;/MudContainer&gt;
                            &lt;/MudTabPanel&gt;
                        }
                    &lt;/ChildContent&gt;
                &lt;/MudTabs&gt;
            }
        &lt;/MudContainer&gt;
    &lt;/DialogContent&gt;
    &lt;DialogActions&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                   OnClick=&quot;CloseModalAsync&quot;&gt;
            @L[&quot;Cancel&quot;]
        &lt;/MudButton&gt;
        &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                   Color=&quot;MudBlazor.Color.Primary&quot; 
                   OnClick=&quot;SaveAsync&quot;&gt;
            @L[&quot;Save&quot;]
        &lt;/MudButton&gt;
    &lt;/DialogActions&gt;
&lt;/MudDialog&gt;
</code></pre>
<hr />
<ol start="2">
<li><code>MudPermissionManagementModal.razor.cs</code></li>
</ol>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using MudBlazor;
using Volo.Abp.AspNetCore.Components.Web.Configuration;
using Volo.Abp.PermissionManagement;
using Volo.Abp.PermissionManagement.Localization;

namespace Acme.BookStore.Blazor.Pages.Identity;

public partial class MudPermissionManagementModal
{
    [Inject] private IPermissionAppService PermissionAppService { get; set; }
    [Inject] private ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; }

    private bool _isVisible;

    protected virtual DialogOptions DialogOptions
    {
        get =&gt; new()
        {
            CloseButton = true,
            CloseOnEscapeKey = true,
            DisableBackdropClick = true,
            MaxWidth = MaxWidth.Medium
        };
    }

    private string _providerName;
    private string _providerKey;

    private string _entityDisplayName;
    private List&lt;PermissionGroupDto&gt; _groups;

    private readonly List&lt;PermissionGrantInfoDto&gt; _disabledPermissions = new();

    private int _grantedPermissionCount = 0;
    private int _notGrantedPermissionCount = 0;

    private bool GrantAll
    {
        get =&gt; _notGrantedPermissionCount == 0;
        set
        {
            if (_groups == null) return;

            _grantedPermissionCount = 0;
            _notGrantedPermissionCount = 0;

            foreach (var permission in _groups.SelectMany(x =&gt; x.Permissions))
            {
                if (IsDisabledPermission(permission)) continue;

                permission.IsGranted = value;

                if (value)
                    _grantedPermissionCount++;
                else
                    _notGrantedPermissionCount++;
            }
        }
    }

    public MudPermissionManagementModal()
    {
        LocalizationResource = typeof(AbpPermissionManagementResource);
    }

    public async Task OpenDialogAsync(string providerName, string providerKey, string entityDisplayName = null)
    {
        try
        {
            _providerName = providerName;
            _providerKey = providerKey;

            var result = await PermissionAppService.GetAsync(_providerName, _providerKey);

            _entityDisplayName = entityDisplayName ?? result.EntityDisplayName;
            _groups = result.Groups;

            _grantedPermissionCount = 0;
            _notGrantedPermissionCount = 0;
            foreach (var permission in _groups.SelectMany(x =&gt; x.Permissions))
            {
                if (permission.IsGranted &amp;&amp; permission.GrantedProviders.All(x =&gt; x.ProviderName != _providerName))
                {
                    _disabledPermissions.Add(permission);
                    continue;
                }

                if (permission.IsGranted)
                    _grantedPermissionCount++;
                else
                    _notGrantedPermissionCount++;
            }

            _isVisible = true;
            StateHasChanged();
        }
        catch (Exception e)
        {
            await HandleErrorAsync(e);
        }
    }

    private async Task CloseModalAsync()
    {
        await InvokeAsync(() =&gt; { _isVisible = false; });
    }

    private async Task SaveAsync()
    {
        try
        {
            var updateDto = new UpdatePermissionsDto
            {
                Permissions = _groups
                    .SelectMany(g =&gt; g.Permissions)
                    .Select(p =&gt; new UpdatePermissionDto { IsGranted = p.IsGranted, Name = p.Name })
                    .ToArray()
            };

            await PermissionAppService.UpdateAsync(_providerName, _providerKey, updateDto);

            await CurrentApplicationConfigurationCacheResetService.ResetAsync();

            await CloseModalAsync();
        }
        catch (Exception e)
        {
            await HandleErrorAsync(e);
        }
    }

    private void GroupGrantAllChanged(bool value, PermissionGroupDto permissionGroup)
    {
        foreach (var permission in permissionGroup.Permissions)
        {
            if (!IsDisabledPermission(permission))
                SetPermissionGrant(permission, value);
        }
    }

    private void PermissionChanged(bool value, PermissionGroupDto permissionGroup, PermissionGrantInfoDto permission)
    {
        SetPermissionGrant(permission, value);

        if (value &amp;&amp; permission.ParentName != null)
        {
            var parentPermission = GetParentPermission(permissionGroup, permission);

            SetPermissionGrant(parentPermission, true);
        }
        else if (value == false)
        {
            var childPermissions = GetChildPermissions(permissionGroup, permission);

            foreach (var childPermission in childPermissions)
            {
                SetPermissionGrant(childPermission, false);
            }
        }
    }

    private void SetPermissionGrant(PermissionGrantInfoDto permission, bool value)
    {
        if (permission.IsGranted == value) return;

        if (value)
        {
            _grantedPermissionCount++;
            _notGrantedPermissionCount--;
        }
        else
        {
            _grantedPermissionCount--;
            _notGrantedPermissionCount++;
        }

        permission.IsGranted = value;
    }

    private static PermissionGrantInfoDto GetParentPermission(PermissionGroupDto permissionGroup, PermissionGrantInfoDto permission)
    {
        return permissionGroup.Permissions.First(x =&gt; x.Name == permission.ParentName);
    }

    private static List&lt;PermissionGrantInfoDto&gt; GetChildPermissions(PermissionGroupDto permissionGroup, PermissionGrantInfoDto permission)
    {
        return permissionGroup.Permissions.Where(x =&gt; x.Name.StartsWith(permission.Name)).ToList();
    }

    private bool IsDisabledPermission(PermissionGrantInfoDto permissionGrantInfo)
    {
        return _disabledPermissions.Any(x =&gt; x == permissionGrantInfo);
    }

    private string GetShownName(PermissionGrantInfoDto permissionGrantInfo)
    {
        if (!IsDisabledPermission(permissionGrantInfo))
            return permissionGrantInfo.DisplayName;

        return string.Format(
            &quot;{0} ({1})&quot;,
            permissionGrantInfo.DisplayName,
            permissionGrantInfo.GrantedProviders
                .Where(p =&gt; p.ProviderName != _providerName)
                .Select(p =&gt; p.ProviderName)
                .JoinAsString(&quot;, &quot;)
        );
    }
}
</code></pre>
<hr />
<ol start="3">
<li><code>MudRoleManagement.razor</code></li>
</ol>
<pre><code class="language-razor">@using MudBlazor;
@using Blazorise
@using Blazorise.DataGrid
@using Volo.Abp.BlazoriseUI
@using Volo.Abp.BlazoriseUI.Components
@using Volo.Abp.Identity
@using Microsoft.AspNetCore.Authorization
@using Volo.Abp.PermissionManagement.Blazor.Components
@using Volo.Abp.Identity.Localization
@using Volo.Abp.AspNetCore.Components.Web
@using Volo.Abp.AspNetCore.Components.Web.Theming
@using Volo.Abp.BlazoriseUI.Components.ObjectExtending
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout
@using Volo.Abp.DependencyInjection
@using Volo.Abp.Identity.Blazor.Pages.Identity
@attribute [Authorize(IdentityPermissions.Roles.Default)]
@attribute [ExposeServices(typeof(RoleManagement))]
@attribute [Dependency(ReplaceServices = true)]
@inject AbpBlazorMessageLocalizerHelper&lt;IdentityResource&gt; LH

@inherits RoleManagement

@* ************************* DATA GRID ************************* *@
&lt;MudDataGrid T=&quot;IdentityRoleDto&quot;
             @ref=&quot;@_dataGrid&quot;
             Elevation=&quot;8&quot;
             Hideable=&quot;true&quot;
             Striped=&quot;true&quot;
             ServerData=&quot;LoadServerData&quot;&gt;
    &lt;ToolBarContent&gt;
        &lt;MudText Typo=&quot;Typo.h5&quot;&gt;@L[&quot;Roles&quot;]&lt;/MudText&gt;
        &lt;MudSpacer /&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Primary&quot;
                   Variant=&quot;Variant.Outlined&quot;
                   Disabled=&quot;!HasCreatePermission&quot;
                   OnClick=&quot;OpenCreateModalAsync&quot;&gt;
            @L[&quot;NewRole&quot;]
        &lt;/MudButton&gt;
    &lt;/ToolBarContent&gt;
    &lt;Columns&gt;
        &lt;MudBlazor.Column T=&quot;IdentityRoleDto&quot;
                          Field=&quot;@nameof(IdentityRoleDto.Id)&quot;
                          Hideable=&quot;false&quot;
                          Title=&quot;@L[&quot;Actions&quot;]&quot;&gt;
            &lt;CellTemplate&gt;
                @if (HasUpdatePermission)
                {
                    &lt;MudIconButton Icon=&quot;fas fa-edit&quot; 
                                   OnClick=&quot;@(async (_) =&gt; { await OpenEditModalAsync(context.Item); })&quot;
                                   Size=&quot;MudBlazor.Size.Small&quot; /&gt;
                    &lt;MudIconButton Icon=&quot;fas fa-user-lock&quot; 
                                   OnClick=&quot;@(async (_) =&gt; { await OpenPermissionsModalAsync(context.Item); })&quot;
                                   Size=&quot;MudBlazor.Size.Small&quot; /&gt;
                }
                @if (HasDeletePermission)
                {   
                    &lt;MudIconButton Icon=&quot;fas fa-trash&quot; 
                                   OnClick=&quot;@(async (_) =&gt; { await DeleteEntityAsync(context.Item);} )&quot;
                                   Size=&quot;MudBlazor.Size.Small&quot; /&gt;
                }
            &lt;/CellTemplate&gt;
        &lt;/MudBlazor.Column&gt;
        &lt;MudBlazor.Column T=&quot;IdentityRoleDto&quot;
                          Field=&quot;@nameof(IdentityRoleDto.Name)&quot;
                          Hideable=&quot;false&quot;
                          Title=@L[&quot;Name&quot;] /&gt;
        &lt;MudBlazor.Column T=&quot;IdentityRoleDto&quot;
                          Field=&quot;@nameof(IdentityRoleDto.Name)&quot;
                          Title=&quot;&quot;&gt;
            &lt;CellTemplate&gt;
                @if (context.Item.IsDefault)
                {
                    &lt;MudChip Color=&quot;MudBlazor.Color.Success&quot;&gt;
                        @L[&quot;DisplayName:IsDefault&quot;]
                    &lt;/MudChip&gt;
                }
                @if (context.Item.IsPublic)
                {
                    &lt;MudChip Color=&quot;MudBlazor.Color.Info&quot;&gt;
                        @L[&quot;DisplayName:IsPublic&quot;]
                    &lt;/MudChip&gt;
                }
            &lt;/CellTemplate&gt;
        &lt;/MudBlazor.Column&gt;
    &lt;/Columns&gt;
&lt;/MudDataGrid&gt;

@* ************************* CREATE MODAL ************************* *@
@if (HasCreatePermission)
{
    &lt;MudDialog @bind-IsVisible=&quot;_createDialogVisible&quot;
               Options=&quot;DialogOptions&quot;&gt;
        &lt;TitleContent&gt;
            &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@L[&quot;NewRole&quot;]&lt;/MudText&gt;
        &lt;/TitleContent&gt;
        &lt;DialogContent&gt;
            &lt;MudForm Model=&quot;@NewEntity&quot;
                     @ref=&quot;_createForm&quot;&gt;
                &lt;MudGrid&gt;
                    &lt;MudItem xs=&quot;12&quot;&gt;
                        &lt;MudTextField @bind-Value=&quot;@NewEntity.Name&quot; 
                                      Label=@L[&quot;Name&quot;]
                                      For=@(() =&gt; NewEntity.Name) /&gt;
                    &lt;/MudItem&gt;
                    &lt;MudItem xs=&quot;6&quot;&gt;
                        &lt;MudCheckBox T=&quot;bool&quot; @bind-Checked=&quot;@NewEntity.IsDefault&quot;&gt;
                            @L[&quot;DisplayName:IsDefault&quot;]
                        &lt;/MudCheckBox&gt;
                    &lt;/MudItem&gt;
                    &lt;MudItem xs=&quot;6&quot;&gt;
                        &lt;MudCheckBox T=&quot;bool&quot; @bind-Checked=&quot;@NewEntity.IsPublic&quot;&gt;
                            @L[&quot;DisplayName:IsPublic&quot;]
                        &lt;/MudCheckBox&gt;
                    &lt;/MudItem&gt;
                &lt;/MudGrid&gt;
            &lt;/MudForm&gt;
        &lt;/DialogContent&gt;
        &lt;DialogActions&gt;
            &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                       OnClick=&quot;CloseCreateModalAsync&quot;&gt;
                @L[&quot;Cancel&quot;]
            &lt;/MudButton&gt;
            &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                       Color=&quot;MudBlazor.Color.Primary&quot; 
                       OnClick=&quot;CreateEntityAsync&quot;&gt;
                @L[&quot;Save&quot;]
            &lt;/MudButton&gt;
        &lt;/DialogActions&gt;
    &lt;/MudDialog&gt;
}

@* ************************* EDIT MODAL ************************* *@
@if (HasUpdatePermission)
{
    &lt;MudDialog @bind-IsVisible=&quot;_editDialogVisible&quot;
               Options=&quot;DialogOptions&quot;&gt;
        &lt;TitleContent&gt;
            &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@L[&quot;Edit&quot;]&lt;/MudText&gt;
        &lt;/TitleContent&gt;
        &lt;DialogContent&gt;
            &lt;MudForm Model=&quot;@EditingEntity&quot;
                     @ref=&quot;_editForm&quot;&gt;
                &lt;MudGrid&gt;
                    &lt;MudItem xs=&quot;12&quot;&gt;
                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.Name&quot; 
                                      Label=@L[&quot;Name&quot;]
                                      For=@(() =&gt; EditingEntity.Name) /&gt;
                    &lt;/MudItem&gt;
                    &lt;MudItem xs=&quot;6&quot;&gt;
                        &lt;MudCheckBox T=&quot;bool&quot; @bind-Checked=&quot;@EditingEntity.IsDefault&quot;&gt;
                            @L[&quot;DisplayName:IsDefault&quot;]
                        &lt;/MudCheckBox&gt;
                    &lt;/MudItem&gt;
                    &lt;MudItem xs=&quot;6&quot;&gt;
                        &lt;MudCheckBox T=&quot;bool&quot; @bind-Checked=&quot;@EditingEntity.IsPublic&quot;&gt;
                            @L[&quot;DisplayName:IsPublic&quot;]
                        &lt;/MudCheckBox&gt;
                    &lt;/MudItem&gt;
                &lt;/MudGrid&gt;
            &lt;/MudForm&gt;
        &lt;/DialogContent&gt;
        &lt;DialogActions&gt;
            &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                       OnClick=&quot;CloseEditModalAsync&quot;&gt;
                @L[&quot;Cancel&quot;]
            &lt;/MudButton&gt;
            &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                       Color=&quot;MudBlazor.Color.Primary&quot; 
                       OnClick=&quot;UpdateEntityAsync&quot;&gt;
                @L[&quot;Save&quot;]
            &lt;/MudButton&gt;
        &lt;/DialogActions&gt;
    &lt;/MudDialog&gt;
}

@if (HasManagePermissionsPermission)
{
    &lt;MudPermissionManagementModal @ref=&quot;_permissionManagementModal&quot;/&gt;
}
</code></pre>
<hr />
<ol start="4">
<li><code>MudRoleManagement.razor.cs</code></li>
</ol>
<pre><code class="language-csharp">using System.Threading.Tasks;
using MudBlazor;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Identity;

namespace Acme.BookStore.Blazor.Pages.Identity;

public partial class MudRoleManagement
{
    private MudForm _createForm;
    private MudForm _editForm;
    private bool _createDialogVisible;
    private bool _editDialogVisible;
    private MudDataGrid&lt;IdentityRoleDto&gt; _dataGrid;
    private MudPermissionManagementModal _permissionManagementModal;

    protected async Task&lt;GridData&lt;IdentityRoleDto&gt;&gt; LoadServerData(GridState&lt;IdentityRoleDto&gt; state)
    {
        if (GetListInput is PagedAndSortedResultRequestDto pageResultRequest)
        {
            pageResultRequest.MaxResultCount = state.PageSize;
            pageResultRequest.SkipCount = state.Page * state.PageSize;
        }
        var result = await AppService.GetListAsync(GetListInput);
        return new()
        {
            Items = result.Items,
            TotalItems = (int)result.TotalCount
        };
    }

    protected override Task OpenCreateModalAsync()
    {
        NewEntity = new();
        _createDialogVisible = true;
        return Task.CompletedTask;
    }

    protected override Task CloseCreateModalAsync()
    {
        _createDialogVisible = false;
        return Task.CompletedTask;
    }

    protected override async Task CreateEntityAsync()
    {
        if (_createForm.IsValid)
        {
            var createDto = MapToCreateInput(NewEntity);
            await AppService.CreateAsync(createDto);
            await _dataGrid.ReloadServerData();
            _createDialogVisible = false;
        }
    }

    protected override Task OpenEditModalAsync(IdentityRoleDto entity)
    {
        EditingEntityId = entity.Id;
        EditingEntity = MapToEditingEntity(entity);
        _editDialogVisible = true;
        return Task.CompletedTask;
    }

    protected override Task CloseEditModalAsync()
    {
        _editDialogVisible = false;
        return Task.CompletedTask;
    }

    protected override async Task UpdateEntityAsync()
    {
        if (_editForm.IsValid)
        {
            await base.UpdateEntityAsync();
            await _dataGrid.ReloadServerData();
            _editDialogVisible = false;
        }
    }

    protected override async Task DeleteEntityAsync(IdentityRoleDto entity)
    {
        if (await Message.Confirm(GetDeleteConfirmationMessage(entity)))
        {
            await base.DeleteEntityAsync(entity);
            await _dataGrid.ReloadServerData();
        }
    }

    protected override Task OnUpdatedEntityAsync()
    {
        return Task.CompletedTask;
    }

    protected virtual async Task OpenPermissionsModalAsync(IdentityRoleDto entity)
    {
        await _permissionManagementModal.OpenDialogAsync(PermissionProviderName, entity.Name);
    }

    protected virtual DialogOptions DialogOptions
    {
        get =&gt; new()
        {
            CloseButton = true,
            CloseOnEscapeKey = true,
            DisableBackdropClick = true
        };
    }
}
</code></pre>
<hr />
<ol start="5">
<li><code>MudUserManagement.razor</code></li>
</ol>
<pre><code class="language-razor">@using Microsoft.AspNetCore.Authorization
@using Volo.Abp.DependencyInjection
@using Volo.Abp.PermissionManagement.Blazor.Components
@using Volo.Abp.Identity.Localization
@using Volo.Abp.AspNetCore.Components.Web.Theming.Layout
@using Volo.Abp.Identity
@using Volo.Abp.Identity.Blazor.Pages.Identity
@attribute [Authorize(IdentityPermissions.Users.Default)]
@attribute [ExposeServices(typeof(UserManagement))]
@attribute [Dependency(ReplaceServices = true)]
@inject AbpBlazorMessageLocalizerHelper&lt;IdentityResource&gt; LH

@inherits UserManagement

@* ************************* DATA GRID ************************* *@
&lt;MudDataGrid T=&quot;IdentityUserDto&quot;
             @ref=&quot;@_dataGrid&quot;
             Striped=&quot;true&quot;
             Elevation=&quot;8&quot;
             Hideable=&quot;true&quot;
             ServerData=&quot;LoadServerData&quot;&gt;
    &lt;ToolBarContent&gt;
        &lt;MudText Typo=&quot;Typo.h5&quot;&gt;@L[&quot;Users&quot;]&lt;/MudText&gt;
        &lt;MudSpacer /&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Primary&quot;
                   Variant=&quot;Variant.Outlined&quot;
                   Disabled=&quot;!HasCreatePermission&quot;
                   OnClick=&quot;OpenCreateModalAsync&quot;&gt;
            @L[&quot;NewUser&quot;]
        &lt;/MudButton&gt;
    &lt;/ToolBarContent&gt;
    &lt;Columns&gt;
        &lt;MudBlazor.Column T=&quot;IdentityUserDto&quot;
                          Field=&quot;@nameof(IdentityUserDto.Id)&quot;
                          Hideable=&quot;false&quot;
                          Title=@L[&quot;Actions&quot;]&gt;
            &lt;CellTemplate&gt;
                @if (HasUpdatePermission)
                {
                    &lt;MudIconButton Icon=&quot;fas fa-edit&quot;
                                   OnClick=&quot;@(async (_) =&gt; { await OpenEditModalAsync(context.Item); })&quot;
                                   Size=&quot;MudBlazor.Size.Small&quot; /&gt;
                    &lt;MudIconButton Icon=&quot;fas fa-user-lock&quot;
                                   OnClick=&quot;@(async (_) =&gt; { await OpenPermissionsModalAsync(context.Item); })&quot;
                                   Size=&quot;MudBlazor.Size.Small&quot; /&gt;
                }
                @if (HasDeletePermission)
                {
                    &lt;MudIconButton Icon=&quot;fas fa-trash&quot;
                                   OnClick=&quot;@(async (_) =&gt; { await DeleteEntityAsync(context.Item);} )&quot;
                                   Size=&quot;MudBlazor.Size.Small&quot; /&gt;
                }
            &lt;/CellTemplate&gt;
        &lt;/MudBlazor.Column&gt;
        &lt;MudBlazor.Column T=&quot;IdentityUserDto&quot;
                          Field=&quot;@nameof(IdentityUserDto.Name)&quot;
                          Hideable=&quot;false&quot;
                          Title=@L[&quot;Name&quot;] /&gt;
        &lt;MudBlazor.Column T=&quot;IdentityUserDto&quot;
                          Field=&quot;@nameof(IdentityUserDto.Email)&quot;
                          Title=@L[&quot;Email&quot;] /&gt;
        &lt;MudBlazor.Column T=&quot;IdentityUserDto&quot;
                          Field=&quot;@nameof(IdentityUserDto.PhoneNumber)&quot;
                          Title=@L[&quot;PhoneNumber&quot;] /&gt;
    &lt;/Columns&gt;
&lt;/MudDataGrid&gt;

@* ************************* CREATE MODAL ************************* *@
@if (HasCreatePermission)
{
    &lt;MudDialog @bind-IsVisible=&quot;_createDialogVisible&quot;
               Options=&quot;DialogOptions&quot;&gt;
        &lt;TitleContent&gt;
            &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@L[&quot;NewUser&quot;]&lt;/MudText&gt;
        &lt;/TitleContent&gt;
        &lt;DialogContent&gt;
            &lt;MudForm Model=&quot;@NewEntity&quot;
                     @ref=&quot;@_createForm&quot;&gt;
                &lt;MudContainer&gt;
                    &lt;MudTabs&gt;
                        &lt;MudTabPanel Text=@L[&quot;UserInformations&quot;]&gt;
                            &lt;MudContainer Style=&quot;width: 450px; height: 450px; overflow-y: scroll&quot;&gt;
                                &lt;MudGrid&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@NewEntity.UserName&quot;
                                                      Label=@L[&quot;DisplayName:UserName&quot;]
                                                      For=&quot;@(() =&gt; NewEntity.UserName)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@NewEntity.Name&quot;
                                                      Label=@L[&quot;DisplayName:Name&quot;]
                                                      For=&quot;@(() =&gt; NewEntity.Name)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@NewEntity.Surname&quot;
                                                      Label=@L[&quot;DisplayName:Surname&quot;]
                                                      For=&quot;@(() =&gt; NewEntity.Surname)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@NewEntity.Password&quot;
                                                      Label=@L[&quot;DisplayName:Password&quot;]
                                                      InputType=&quot;InputType.Password&quot;
                                                      For=&quot;@(() =&gt; NewEntity.Password)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@NewEntity.Email&quot;
                                                      Label=@L[&quot;DisplayName:Email&quot;]
                                                      InputType=&quot;InputType.Email&quot;
                                                      For=&quot;@(() =&gt; NewEntity.Email)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@NewEntity.PhoneNumber&quot;
                                                      Label=@L[&quot;DisplayName:PhoneNumber&quot;]
                                                      InputType=&quot;InputType.Telephone&quot;
                                                      For=&quot;@(() =&gt; NewEntity.PhoneNumber)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudCheckBox TValue=&quot;bool&quot; 
                                                     @bind-Checked=&quot;@NewEntity.IsActive&quot;&gt;
                                            @L[&quot;DisplayName:IsActive&quot;]
                                        &lt;/MudCheckBox&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudCheckBox TValue=&quot;bool&quot; 
                                                     @bind-Checked=&quot;@NewEntity.LockoutEnabled&quot;&gt;
                                            @L[&quot;DisplayName:LockoutEnabled&quot;]
                                        &lt;/MudCheckBox&gt;
                                    &lt;/MudItem&gt;
                                &lt;/MudGrid&gt;
                            &lt;/MudContainer&gt;
                        &lt;/MudTabPanel&gt;
                        &lt;MudTabPanel Text=@L[&quot;Roles&quot;]&gt;
                            &lt;MudContainer Style=&quot;width: 450px; height: 450px; overflow-y: scroll&quot;&gt;
                                &lt;MudGrid&gt;
                                    @if (NewUserRoles != null)
                                    {
                                        @foreach (var role in NewUserRoles)
                                        {
                                            &lt;MudItem xs=&quot;12&quot;&gt;
                                                &lt;MudCheckBox TValue=&quot;bool&quot; 
                                                             @bind-Checked=&quot;@role.IsAssigned&quot;&gt;
                                                    @role.Name
                                                &lt;/MudCheckBox&gt;
                                            &lt;/MudItem&gt;
                                        }
                                    }
                                    else
                                    {
                                        &lt;MudItem xs=&quot;12&quot;&gt;
                                            &lt;MudText&gt;N/A&lt;/MudText&gt;
                                        &lt;/MudItem&gt;
                                    }
                                &lt;/MudGrid&gt;
                            &lt;/MudContainer&gt;
                        &lt;/MudTabPanel&gt;
                    &lt;/MudTabs&gt;
                &lt;/MudContainer&gt;
            &lt;/MudForm&gt;
        &lt;/DialogContent&gt;
        &lt;DialogActions&gt;
            &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                       OnClick=&quot;CloseCreateModalAsync&quot;&gt;
                @L[&quot;Cancel&quot;]
            &lt;/MudButton&gt;
            &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                       Color=&quot;MudBlazor.Color.Primary&quot; 
                       OnClick=&quot;CreateEntityAsync&quot;&gt;
                @L[&quot;Save&quot;]
            &lt;/MudButton&gt;
        &lt;/DialogActions&gt;
    &lt;/MudDialog&gt;
}

@* ************************* EDIT MODAL ************************* *@
@if (HasUpdatePermission)
{
    &lt;MudDialog @bind-IsVisible=&quot;_editDialogVisible&quot;
               Options=&quot;DialogOptions&quot;&gt;
        &lt;TitleContent&gt;
            &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@L[&quot;Edit&quot;]&lt;/MudText&gt;
        &lt;/TitleContent&gt;
        &lt;DialogContent&gt;
            &lt;MudForm Model=&quot;@EditingEntity&quot;
                     @ref=&quot;@_editForm&quot;&gt;
                &lt;MudContainer&gt;
                    &lt;MudTabs&gt;
                        &lt;MudTabPanel Text=@L[&quot;UserInformations&quot;]&gt;
                            &lt;MudContainer Style=&quot;width: 450px; height: 450px; overflow-y: scroll&quot;&gt;
                                &lt;MudGrid&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.UserName&quot;
                                                      Label=@L[&quot;DisplayName:UserName&quot;]
                                                      For=&quot;@(() =&gt; EditingEntity.UserName)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.Name&quot;
                                                      Label=@L[&quot;DisplayName:Name&quot;]
                                                      For=&quot;@(() =&gt; EditingEntity.Name)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.Surname&quot;
                                                      Label=@L[&quot;DisplayName:Surname&quot;]
                                                      For=&quot;@(() =&gt; EditingEntity.Surname)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.Password&quot;
                                                      Label=@L[&quot;DisplayName:Password&quot;]
                                                      InputType=&quot;InputType.Password&quot;
                                                      For=&quot;@(() =&gt; EditingEntity.Password)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.Email&quot;
                                                      Label=@L[&quot;DisplayName:Email&quot;]
                                                      InputType=&quot;InputType.Email&quot;
                                                      For=&quot;@(() =&gt; EditingEntity.Email)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudTextField @bind-Value=&quot;@EditingEntity.PhoneNumber&quot;
                                                      Label=@L[&quot;DisplayName:PhoneNumber&quot;]
                                                      InputType=&quot;InputType.Telephone&quot;
                                                      For=&quot;@(() =&gt; EditingEntity.PhoneNumber)&quot; /&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudCheckBox TValue=&quot;bool&quot; 
                                                     @bind-Checked=&quot;@EditingEntity.IsActive&quot;&gt;
                                            @L[&quot;DisplayName:IsActive&quot;]
                                        &lt;/MudCheckBox&gt;
                                    &lt;/MudItem&gt;
                                    &lt;MudItem xs=&quot;12&quot;&gt;
                                        &lt;MudCheckBox TValue=&quot;bool&quot; 
                                                     @bind-Checked=&quot;@EditingEntity.LockoutEnabled&quot;&gt;
                                            @L[&quot;DisplayName:LockoutEnabled&quot;]
                                        &lt;/MudCheckBox&gt;
                                    &lt;/MudItem&gt;
                                &lt;/MudGrid&gt;
                            &lt;/MudContainer&gt;
                        &lt;/MudTabPanel&gt;
                        &lt;MudTabPanel Text=@L[&quot;Roles&quot;]&gt;
                            &lt;MudContainer Style=&quot;width: 450px; height: 450px; overflow-y: scroll&quot;&gt;
                                &lt;MudGrid&gt;
                                    @if (EditUserRoles != null)
                                    {
                                        @foreach (var role in EditUserRoles)
                                        {
                                            &lt;MudItem xs=&quot;12&quot;&gt;
                                                &lt;MudCheckBox TValue=&quot;bool&quot; 
                                                             @bind-Checked=&quot;@role.IsAssigned&quot;&gt;
                                                    @role.Name
                                                &lt;/MudCheckBox&gt;
                                            &lt;/MudItem&gt;
                                        }
                                    }
                                    else
                                    {
                                        &lt;MudItem xs=&quot;12&quot;&gt;
                                            &lt;MudText&gt;N/A&lt;/MudText&gt;
                                        &lt;/MudItem&gt;
                                    }
                                &lt;/MudGrid&gt;
                            &lt;/MudContainer&gt;
                        &lt;/MudTabPanel&gt;
                    &lt;/MudTabs&gt;
                &lt;/MudContainer&gt;
            &lt;/MudForm&gt;
        &lt;/DialogContent&gt;
        &lt;DialogActions&gt;
            &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                       OnClick=&quot;CloseEditModalAsync&quot;&gt;
                @L[&quot;Cancel&quot;]
            &lt;/MudButton&gt;
            &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                       Color=&quot;MudBlazor.Color.Primary&quot; 
                       OnClick=&quot;UpdateEntityAsync&quot;&gt;
                @L[&quot;Save&quot;]
            &lt;/MudButton&gt;
        &lt;/DialogActions&gt;
    &lt;/MudDialog&gt;
}

@if (HasManagePermissionsPermission)
{
    &lt;MudPermissionManagementModal @ref=&quot;_permissionManagementModal&quot; /&gt;
}
</code></pre>
<hr />
<ol start="6">
<li><code>MudUserManagement.razor.cs</code></li>
</ol>
<pre><code class="language-csharp">using System.Linq;
using System.Threading.Tasks;
using MudBlazor;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Identity;
using Volo.Abp.Identity.Blazor.Pages.Identity;

namespace Acme.BookStore.Blazor.Pages.Identity;

public partial class MudUserManagement
{
    private MudForm _createForm;
    private MudForm _editForm;
    private bool _createDialogVisible;
    private bool _editDialogVisible;
    private MudDataGrid&lt;IdentityUserDto&gt; _dataGrid;
    private MudPermissionManagementModal _permissionManagementModal;

    protected async Task&lt;GridData&lt;IdentityUserDto&gt;&gt; LoadServerData(GridState&lt;IdentityUserDto&gt; state)
    {
        if (GetListInput is PagedAndSortedResultRequestDto pageResultRequest)
        {
            pageResultRequest.MaxResultCount = state.PageSize;
            pageResultRequest.SkipCount = state.Page * state.PageSize;
        }
        var result = await AppService.GetListAsync(GetListInput);
        return new()
        {
            Items = result.Items,
            TotalItems = (int)result.TotalCount
        };
    }

    protected override Task OpenCreateModalAsync()
    {
        NewEntity = new() { IsActive = true };
        NewUserRoles = Roles.Select(i =&gt; new AssignedRoleViewModel
        {
            Name = i.Name,
            IsAssigned = i.IsDefault
        }).ToArray();
        _createDialogVisible = true;
        return Task.CompletedTask;
    }

    protected override Task CloseCreateModalAsync()
    {
        _createDialogVisible = false;
        return Task.CompletedTask;
    }

    protected override async Task CreateEntityAsync()
    {
        if (_createForm.IsValid)
        {
            var createDto = MapToCreateInput(NewEntity);
            await AppService.CreateAsync(createDto);
            await _dataGrid.ReloadServerData();
            await CloseCreateModalAsync();
        }
    }

    protected override async Task OpenEditModalAsync(IdentityUserDto entity)
    {
        var userRoleNames = (await AppService.GetRolesAsync(entity.Id)).Items.Select(r =&gt; r.Name).ToList();
        EditUserRoles = Roles.Select(x =&gt; new AssignedRoleViewModel
        {
            Name = x.Name,
            IsAssigned = userRoleNames.Contains(x.Name)
        }).ToArray();
        EditingEntityId = entity.Id;
        EditingEntity = MapToEditingEntity(entity);
        _editDialogVisible = true;
    }

    protected override Task CloseEditModalAsync()
    {
        _editDialogVisible = false;
        return Task.CompletedTask;
    }

    protected override async Task UpdateEntityAsync()
    {
        if (_editForm.IsValid)
        {
            await AppService.UpdateAsync(EditingEntityId, EditingEntity);
            await _dataGrid.ReloadServerData();
            await CloseEditModalAsync();
        }
    }

    protected override async Task DeleteEntityAsync(IdentityUserDto entity)
    {
        if (await Message.Confirm(GetDeleteConfirmationMessage(entity)))
        {
            await base.DeleteEntityAsync(entity);
            await _dataGrid.ReloadServerData();
        }
    }

    protected override Task OnUpdatedEntityAsync()
    {
        return Task.CompletedTask;
    }

    protected virtual async Task OpenPermissionsModalAsync(IdentityUserDto entity)
    {
        await _permissionManagementModal.OpenDialogAsync(
            PermissionProviderName, entity.Id.ToString());
    }

    protected virtual DialogOptions DialogOptions
    {
        get =&gt; new()
        {
            CloseButton = true,
            CloseOnEscapeKey = true,
            DisableBackdropClick = true
        };
    }
}
</code></pre>
<hr />
<h2>Screenshots</h2>
<p><img src="https://raw.githubusercontent.com/yellow-dragon-cloud/AbpMudBlazorFinal/main/images/screenshot5.png" alt="image" /></p>
<p><img src="https://raw.githubusercontent.com/yellow-dragon-cloud/AbpMudBlazorFinal/main/images/screenshot6.png" alt="image" /></p>
<h2>Source Code</h2>
<p>The source code of this project is <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazorFinal">available on Github</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/9ee28bbb-8b80-ea4c-3793-3a02eacd88bd" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/9ee28bbb-8b80-ea4c-3793-3a02eacd88bd" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-part-4-e67wqom3</guid>
      <link>https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-part-4-e67wqom3</link>
      <a10:author>
        <a10:name>a-urel</a10:name>
        <a10:uri>https://abp.io/community/members/a-urel</a10:uri>
      </a10:author>
      <category>blazor-wasm</category>
      <category>MudBlazor</category>
      <title>MudBlazor Theme in ABP Blazor WebAssembly PART 4</title>
      <description>In this part, I'll show how to create CRUD pages with MudBlazor components.</description>
      <pubDate>Sat, 26 Mar 2022 23:03:22 Z</pubDate>
      <a10:updated>2026-03-08T10:37:00Z</a10:updated>
      <content:encoded><![CDATA[<h1>MudBlazor Theme in ABP Blazor WebAssembly PART 4</h1>
<h2>Introduction</h2>
<p>In this part, I'll show how to create CRUD pages with <a href="https://www.mudblazor.com/">MudBlazor</a> components.</p>
<h2>11. Make Sure You Have Completed Previous Parts</h2>
<p>You must complete the steps in <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor">Part 1</a>, <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor2">Part 2</a>, and <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor3">Part 3</a> to continue.</p>
<h2>12. Create CRUD Pages</h2>
<p>Complete the <strong>Web Application Development Tutorial</strong> in <strong>ABP documentation</strong>:</p>
<ul>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-1?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 1: Creating the Server Side</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-2?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 2: The Book List Page</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-3?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 3: Creating, Updating and Deleting Books</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-4?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 4: Integration Tests</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-5?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 5: Authorization</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-6?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 6: Authors: Domain Layer</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-7?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 7: Authors: Database Integration</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-8?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 8: Authors: Application Layer</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-9?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 9: Authors: User Interface</a></li>
<li><a href="https://docs.abp.io/en/abp/latest/Tutorials/Part-10?UI=Blazor&amp;DB=Mongo">Web Application Development Tutorial - Part 10: Book to Author Relation</a></li>
</ul>
<h2>13. Update <strong>Authors</strong> CRUD Page</h2>
<p>Add <code>@using MudBlazor</code> to <code>Acme.BookStore.Blazor/_Imports.razor</code></p>
<p>Update <code>Authors.razor</code> with the following content:</p>
<pre><code class="language-razor">@page &quot;/authors&quot;
@using Acme.BookStore.Authors
@using Acme.BookStore.Localization
@using Volo.Abp.AspNetCore.Components.Web
@inherits BookStoreComponentBase
@inject IAuthorAppService AuthorAppService
@inject AbpBlazorMessageLocalizerHelper&lt;BookStoreResource&gt; LH

&lt;MudDataGrid T=&quot;AuthorDto&quot;
             @ref=&quot;_authorList&quot;
             Elevation=&quot;8&quot;
             Hideable=&quot;true&quot;
             Striped=&quot;true&quot;
             ServerData=&quot;LoadServerData&quot;&gt;
&lt;ToolBarContent&gt;
    &lt;MudText Typo=&quot;Typo.h5&quot;&gt;@L[&quot;Authors&quot;]&lt;/MudText&gt;
    &lt;MudSpacer /&gt;
    &lt;MudButton Color=&quot;MudBlazor.Color.Primary&quot;
               Variant=&quot;Variant.Outlined&quot;
               Disabled=&quot;!CanCreateAuthor&quot;
               OnClick=&quot;OpenCreateAuthorModal&quot;&gt;
        @L[&quot;NewAuthor&quot;]
    &lt;/MudButton&gt;
&lt;/ToolBarContent&gt;
&lt;Columns&gt;
    &lt;MudBlazor.Column T=&quot;AuthorDto&quot;
                      Field=&quot;@nameof(AuthorDto.Id)&quot;
                      Hideable=&quot;false&quot;
                      Title=&quot;@L[&quot;Actions&quot;]&quot;&gt;
        &lt;CellTemplate&gt;
            @if (CanEditAuthor)
            {
                &lt;MudIconButton Icon=&quot;fas fa-edit&quot; 
                               OnClick=&quot;@((e) =&gt; {OpenEditAuthorModal(context.Item);})&quot;
                               Size=&quot;MudBlazor.Size.Small&quot; /&gt;
            }
            @if (CanDeleteAuthor)
            {   
                &lt;MudIconButton Icon=&quot;fas fa-trash&quot; 
                               OnClick=&quot;@(async (e) =&gt; {await DeleteAuthorAsync(context.Item);})&quot;
                               Size=&quot;MudBlazor.Size.Small&quot; /&gt;
            }
        &lt;/CellTemplate&gt;
    &lt;/MudBlazor.Column&gt;
    &lt;MudBlazor.Column T=&quot;AuthorDto&quot;
                      Field=&quot;@nameof(AuthorDto.Name)&quot;
                      Hideable=&quot;false&quot;
                      Title=&quot;@L[&quot;Name&quot;]&quot; /&gt;
    &lt;MudBlazor.Column T=&quot;AuthorDto&quot;
                      Field=&quot;@nameof(AuthorDto.BirthDate)&quot;
                      Title=&quot;@L[&quot;BirthDate&quot;]&quot;&gt;
        &lt;CellTemplate&gt;
            @context.Item.BirthDate?.ToShortDateString()
        &lt;/CellTemplate&gt;
    &lt;/MudBlazor.Column&gt;
&lt;/Columns&gt;
&lt;/MudDataGrid&gt;

&lt;MudDialog @bind-IsVisible=&quot;_createAuthorDialogVisible&quot;&gt;
    &lt;TitleContent&gt;
        &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@L[&quot;NewAuthor&quot;]&lt;/MudText&gt;
    &lt;/TitleContent&gt;
    &lt;DialogContent&gt;
        &lt;MudForm Model=&quot;@NewAuthor&quot;
                 @ref=&quot;_createForm&quot;&gt;
            &lt;MudTextField @bind-Value=&quot;@NewAuthor.Name&quot; 
                          Label=@L[&quot;Name&quot;]
                          For=@(() =&gt; NewAuthor.Name) /&gt;
            &lt;br /&gt;
            &lt;MudDatePicker @bind-Date=&quot;@NewAuthor.BirthDate&quot; 
                           Editable=&quot;true&quot;
                           Mask=&quot;@(new DateMask(&quot;dd.MM.yyyy&quot;))&quot; 
                           DateFormat=&quot;dd.MM.yyyy&quot;
                           Label=@L[&quot;BirthDate&quot;] /&gt;
            &lt;br /&gt;
            &lt;MudTextField @bind-Value=&quot;@NewAuthor.ShortBio&quot; 
                          Label=@L[&quot;ShortBio&quot;]
                          Lines=&quot;5&quot;
                          For=@(() =&gt; NewAuthor.ShortBio) /&gt;
        &lt;/MudForm&gt;
    &lt;/DialogContent&gt;
    &lt;DialogActions&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                   OnClick=&quot;CloseCreateAuthorModal&quot;&gt;
            @L[&quot;Cancel&quot;]
        &lt;/MudButton&gt;
        &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                   Color=&quot;MudBlazor.Color.Primary&quot; 
                   OnClick=&quot;CreateAuthorAsync&quot;&gt;
            @L[&quot;Save&quot;]
        &lt;/MudButton&gt;
    &lt;/DialogActions&gt;
&lt;/MudDialog&gt;

&lt;MudDialog @bind-IsVisible=&quot;_editAuthorDialogVisible&quot;&gt;
    &lt;TitleContent&gt;
        &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@EditingAuthor.Name&lt;/MudText&gt;
    &lt;/TitleContent&gt;
    &lt;DialogContent&gt;
        &lt;MudForm Model=&quot;@EditingAuthor&quot;
                 @ref=&quot;_editForm&quot;&gt;
            &lt;MudTextField @bind-Value=&quot;@EditingAuthor.Name&quot; 
                          Label=@L[&quot;Name&quot;]
                          For=@(() =&gt; EditingAuthor.Name) /&gt;
            &lt;br /&gt;
            &lt;MudDatePicker @bind-Date=&quot;@EditingAuthor.BirthDate&quot; 
                           Editable=&quot;true&quot;
                           Mask=&quot;@(new DateMask(&quot;dd.MM.yyyy&quot;))&quot; 
                           DateFormat=&quot;dd.MM.yyyy&quot;
                           Label=@L[&quot;BirthDate&quot;] /&gt;
            &lt;br /&gt;
            &lt;MudTextField @bind-Value=&quot;@EditingAuthor.ShortBio&quot; 
                          Label=@L[&quot;ShortBio&quot;]
                          Lines=&quot;5&quot;
                          For=@(() =&gt; EditingAuthor.ShortBio) /&gt;
        &lt;/MudForm&gt;
    &lt;/DialogContent&gt;
    &lt;DialogActions&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                   OnClick=&quot;CloseEditAuthorModal&quot;&gt;
            @L[&quot;Cancel&quot;]
        &lt;/MudButton&gt;
        &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                   Color=&quot;MudBlazor.Color.Primary&quot; 
                   OnClick=&quot;UpdateAuthorAsync&quot;&gt;
            @L[&quot;Save&quot;]
        &lt;/MudButton&gt;
    &lt;/DialogActions&gt;
&lt;/MudDialog&gt;
</code></pre>
<p>Then, update <code>Authors.razor.cs</code> code behing file with the following content:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Acme.BookStore.Authors;
using Acme.BookStore.Permissions;
using Microsoft.AspNetCore.Authorization;
using MudBlazor;

namespace Acme.BookStore.Blazor.Pages
{
    public partial class Authors
    {
        private async Task&lt;GridData&lt;AuthorDto&gt;&gt; LoadServerData(GridState&lt;AuthorDto&gt; state)
        {
            var input = new GetAuthorListDto 
            { 
                Filter = &quot;&quot;, 
                MaxResultCount = state.PageSize, 
                SkipCount = state.Page * state.PageSize
            };
            var result = await AuthorAppService.GetListAsync(input);
            return new()
            {
                Items = result.Items,
                TotalItems = (int)result.TotalCount
            };
        }

        private bool CanCreateAuthor { get; set; }
        private bool CanEditAuthor { get; set; }
        private bool CanDeleteAuthor { get; set; }

        private MudDataGrid&lt;AuthorDto&gt; _authorList;

        private CreateAuthorDto NewAuthor { get; set; }

        private bool _createAuthorDialogVisible;
        private bool _editAuthorDialogVisible;

        private MudForm _createForm;
        private MudForm _editForm;

        private Guid EditingAuthorId { get; set; }
        private UpdateAuthorDto EditingAuthor { get; set; }

        public Authors()
        {
            NewAuthor = new CreateAuthorDto();
            EditingAuthor = new UpdateAuthorDto();
        }

        protected override async Task OnInitializedAsync()
        {
            await SetPermissionsAsync();
        }

        private async Task SetPermissionsAsync()
        {
            CanCreateAuthor = await AuthorizationService
                .IsGrantedAsync(BookStorePermissions.Authors.Create);

            CanEditAuthor = await AuthorizationService
                .IsGrantedAsync(BookStorePermissions.Authors.Edit);

            CanDeleteAuthor = await AuthorizationService
                .IsGrantedAsync(BookStorePermissions.Authors.Delete);
        }

        private void OpenCreateAuthorModal()
        {
            NewAuthor = new CreateAuthorDto();
            _createAuthorDialogVisible = true;
        }

        private void CloseCreateAuthorModal()
        {
            _createAuthorDialogVisible = false;
        }

        private void OpenEditAuthorModal(AuthorDto author)
        {
            EditingAuthorId = author.Id;
            EditingAuthor = ObjectMapper.Map&lt;AuthorDto, UpdateAuthorDto&gt;(author);
            _editAuthorDialogVisible = true;
        }

        private async Task DeleteAuthorAsync(AuthorDto author)
        {
            var confirmMessage = L[&quot;AuthorDeletionConfirmationMessage&quot;, author.Name];
            if (!await Message.Confirm(confirmMessage))
            {
                return;
            }

            await AuthorAppService.DeleteAsync(author.Id);
            await _authorList.ReloadServerData();
        }

        private void CloseEditAuthorModal()
        {
            _editAuthorDialogVisible = false;
        }

        private async Task CreateAuthorAsync()
        {
            if (_createForm.IsValid)
            {
                await AuthorAppService.CreateAsync(NewAuthor);
                _createAuthorDialogVisible = false;
                await _authorList.ReloadServerData();
            }
        }

        private async Task UpdateAuthorAsync()
        {
            if (_editForm.IsValid)
            {
                await AuthorAppService.UpdateAsync(EditingAuthorId, EditingAuthor);
                _editAuthorDialogVisible = false;
                await _authorList.ReloadServerData();
            }
        }
    }
}
</code></pre>
<p>Change type of <code>BirthDate</code> property in <code>Author</code>, <code>AuthorDto</code>, <code>CreateAuthorDto</code>, <code>UpdateAuthorDto</code> from <code>DateTime</code> to <code>DateTime?</code></p>
<p>Now, the <strong>Authors</strong> page should look like this:</p>
<p><img src="https://raw.githubusercontent.com/yellow-dragon-cloud/AbpMudBlazor4/main/images/screenshot4.png" alt="image" /></p>
<h2>14. Define <code>MudCrudPageBase</code> Class</h2>
<p>Create <code>MudCrudPageBase.cs</code> file in <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme/Components</code> and paste the following code:</p>
<pre><code class="language-csharp">using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Localization.Resources.AbpUi;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using MudBlazor;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Authorization;
using Volo.Abp.BlazoriseUI.Components;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions;
using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns;

namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Components;

public abstract class MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey&gt;
    : MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey,
        PagedAndSortedResultRequestDto&gt;
    where TAppService : ICrudAppService&lt;
        TEntityDto,
        TKey&gt;
    where TEntityDto : class, IEntityDto&lt;TKey&gt;, new()
{
}

public abstract class MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey,
        TGetListInput&gt;
    : MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey,
        TGetListInput,
        TEntityDto&gt;
    where TAppService : ICrudAppService&lt;
        TEntityDto,
        TKey,
        TGetListInput&gt;
    where TEntityDto : class, IEntityDto&lt;TKey&gt;, new()
    where TGetListInput : new()
{
}

public abstract class MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey,
        TGetListInput,
        TCreateInput&gt;
    : MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TCreateInput&gt;
    where TAppService : ICrudAppService&lt;
        TEntityDto,
        TKey,
        TGetListInput,
        TCreateInput&gt;
    where TEntityDto : IEntityDto&lt;TKey&gt;
    where TCreateInput : class, new()
    where TGetListInput : new()
{
}

public abstract class MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput&gt;
    : MudCrudPageBase&lt;
        TAppService,
        TEntityDto,
        TEntityDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput&gt;
    where TAppService : ICrudAppService&lt;
        TEntityDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput&gt;
    where TEntityDto : IEntityDto&lt;TKey&gt;
    where TCreateInput : class, new()
    where TUpdateInput : class, new()
    where TGetListInput : new()
{
}

public abstract class MudCrudPageBase&lt;
        TAppService,
        TGetOutputDto,
        TGetListOutputDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput&gt;
    : MudCrudPageBase&lt;
        TAppService,
        TGetOutputDto,
        TGetListOutputDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput,
        TGetListOutputDto,
        TCreateInput,
        TUpdateInput&gt;
    where TAppService : ICrudAppService&lt;
        TGetOutputDto,
        TGetListOutputDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput&gt;
    where TGetOutputDto : IEntityDto&lt;TKey&gt;
    where TGetListOutputDto : IEntityDto&lt;TKey&gt;
    where TCreateInput : class, new()
    where TUpdateInput : class, new()
    where TGetListInput : new()
{
}

public abstract class MudCrudPageBase&lt;
        TAppService,
        TGetOutputDto,
        TGetListOutputDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput,
        TListViewModel,
        TCreateViewModel,
        TUpdateViewModel&gt;
    : AbpComponentBase
    where TAppService : ICrudAppService&lt;
        TGetOutputDto,
        TGetListOutputDto,
        TKey,
        TGetListInput,
        TCreateInput,
        TUpdateInput&gt;
    where TGetOutputDto : IEntityDto&lt;TKey&gt;
    where TGetListOutputDto : IEntityDto&lt;TKey&gt;
    where TCreateInput : class
    where TUpdateInput : class
    where TGetListInput : new()
    where TListViewModel : IEntityDto&lt;TKey&gt;
    where TCreateViewModel : class, new()
    where TUpdateViewModel : class, new()
{
    [Inject] protected TAppService AppService { get; set; }
    [Inject] protected IStringLocalizer&lt;AbpUiResource&gt; UiLocalizer { get; set; }

    protected virtual int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount;

    protected TGetListInput GetListInput = new();
    protected TCreateViewModel NewEntity;
    protected TKey EditingEntityId;
    protected TUpdateViewModel EditingEntity;

    protected MudDataGrid&lt;TListViewModel&gt; DataGrid;

    protected bool CreateDialogVisible;
    protected bool EditDialogVisible;
    
    protected MudForm CreateForm;
    protected MudForm EditForm;

    protected DataGridEntityActionsColumn&lt;TListViewModel&gt; EntityActionsColumn;
    protected EntityActionDictionary EntityActions { get; set; }
    protected TableColumnDictionary TableColumns { get; set; }

    protected string CreatePolicyName { get; set; }
    protected string UpdatePolicyName { get; set; }
    protected string DeletePolicyName { get; set; }

    public bool HasCreatePermission { get; set; }
    public bool HasUpdatePermission { get; set; }
    public bool HasDeletePermission { get; set; }

    protected DialogOptions DialogOptions 
    {
        get =&gt; new()
        { 
            CloseButton = true,
            CloseOnEscapeKey = true,
            DisableBackdropClick = true
        };
    }

    protected MudCrudPageBase()
    {
        NewEntity = new TCreateViewModel();
        EditingEntity = new TUpdateViewModel();
        TableColumns = new TableColumnDictionary();
        EntityActions = new EntityActionDictionary();
    }

    protected async override Task OnInitializedAsync()
    {
        await SetPermissionsAsync();
        await SetEntityActionsAsync();
        await SetTableColumnsAsync();
        await InvokeAsync(StateHasChanged);
    }

    protected async override Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await base.OnAfterRenderAsync(firstRender);
            await SetToolbarItemsAsync();
            await SetBreadcrumbItemsAsync();
        }
    }

    protected virtual async Task SetPermissionsAsync()
    {
        if (CreatePolicyName != null)
        {
            HasCreatePermission = await AuthorizationService.IsGrantedAsync(CreatePolicyName);
        }

        if (UpdatePolicyName != null)
        {
            HasUpdatePermission = await AuthorizationService.IsGrantedAsync(UpdatePolicyName);
        }

        if (DeletePolicyName != null)
        {
            HasDeletePermission = await AuthorizationService.IsGrantedAsync(DeletePolicyName);
        }
    }

    private IReadOnlyList&lt;TListViewModel&gt; MapToListViewModel(IReadOnlyList&lt;TGetListOutputDto&gt; dtos)
    {
        if (typeof(TGetListOutputDto) == typeof(TListViewModel))
        {
            return dtos.As&lt;IReadOnlyList&lt;TListViewModel&gt;&gt;();
        }

        return ObjectMapper.Map&lt;IReadOnlyList&lt;TGetListOutputDto&gt;, List&lt;TListViewModel&gt;&gt;(dtos);
    }

    protected async Task&lt;GridData&lt;TListViewModel&gt;&gt; LoadServerData(GridState&lt;TListViewModel&gt; state)
    {
        if (GetListInput is PagedAndSortedResultRequestDto pageResultRequest)
        {
            pageResultRequest.MaxResultCount = state.PageSize;
            pageResultRequest.SkipCount = state.Page * state.PageSize;
        }
        var result = await AppService.GetListAsync(GetListInput);
        return new()
        {
            Items = MapToListViewModel(result.Items),
            TotalItems = (int)result.TotalCount
        };
    }

    protected virtual async Task OpenCreateModalAsync()
    {
        try
        {
            await CheckCreatePolicyAsync();

            NewEntity = new TCreateViewModel();

            // Mapper will not notify Blazor that binded values are changed
            // so we need to notify it manually by calling StateHasChanged
            await InvokeAsync(() =&gt;
            {
                StateHasChanged();
                CreateDialogVisible = true;
            });
        }
        catch (Exception ex)
        {
            await HandleErrorAsync(ex);
        }
    }

    protected virtual Task CloseCreateModalAsync()
    {
        NewEntity = new TCreateViewModel();
        return InvokeAsync(() =&gt; { CreateDialogVisible = false; });
    }

    protected virtual async Task OpenEditModalAsync(TListViewModel entity)
    {
        try
        {
            await CheckUpdatePolicyAsync();

            var entityDto = await AppService.GetAsync(entity.Id);

            EditingEntityId = entity.Id;
            EditingEntity = MapToEditingEntity(entityDto);

            await InvokeAsync(() =&gt;
            {
                StateHasChanged();
                EditDialogVisible = true;
            });
        }
        catch (Exception ex)
        {
            await HandleErrorAsync(ex);
        }
    }

    protected virtual TUpdateViewModel MapToEditingEntity(TGetOutputDto entityDto)
    {
        return ObjectMapper.Map&lt;TGetOutputDto, TUpdateViewModel&gt;(entityDto);
    }

    protected virtual TCreateInput MapToCreateInput(TCreateViewModel createViewModel)
    {
        if (typeof(TCreateInput) == typeof(TCreateViewModel))
        {
            return createViewModel.As&lt;TCreateInput&gt;();
        }

        return ObjectMapper.Map&lt;TCreateViewModel, TCreateInput&gt;(createViewModel);
    }

    protected virtual TUpdateInput MapToUpdateInput(TUpdateViewModel updateViewModel)
    {
        if (typeof(TUpdateInput) == typeof(TUpdateViewModel))
        {
            return updateViewModel.As&lt;TUpdateInput&gt;();
        }

        return ObjectMapper.Map&lt;TUpdateViewModel, TUpdateInput&gt;(updateViewModel);
    }

    protected virtual Task CloseEditModalAsync()
    {
        InvokeAsync(() =&gt; { EditDialogVisible = false; });
        return Task.CompletedTask;
    }

    protected virtual async Task CreateEntityAsync()
    {
        try
        {
            var validate = true;
            if (CreateForm is not null)
            {
                validate = CreateForm.IsValid;
            }
            if (validate)
            {
                await OnCreatingEntityAsync();

                await CheckCreatePolicyAsync();
                var createInput = MapToCreateInput(NewEntity);
                await AppService.CreateAsync(createInput);

                await OnCreatedEntityAsync();
            }
        }
        catch (Exception ex)
        {
            await HandleErrorAsync(ex);
        }
    }

    protected virtual Task OnCreatingEntityAsync()
    {
        return Task.CompletedTask;
    }

    protected virtual async Task OnCreatedEntityAsync()
    {
        NewEntity = new TCreateViewModel();
        await DataGrid.ReloadServerData();

        await InvokeAsync(() =&gt; { CreateDialogVisible = false; });
    }

    protected virtual async Task UpdateEntityAsync()
    {
        try
        {
            var validate = true;
            if (EditForm is not null)
            {
                validate = EditForm.IsValid;
            }
            if (validate)
            {
                await OnUpdatingEntityAsync();

                await CheckUpdatePolicyAsync();
                var updateInput = MapToUpdateInput(EditingEntity);
                await AppService.UpdateAsync(EditingEntityId, updateInput);

                await OnUpdatedEntityAsync();
            }
        }
        catch (Exception ex)
        {
            await HandleErrorAsync(ex);
        }
    }

    protected virtual Task OnUpdatingEntityAsync()
    {
        return Task.CompletedTask;
    }

    protected virtual async Task OnUpdatedEntityAsync()
    {
        await DataGrid.ReloadServerData();

        await InvokeAsync(() =&gt; { EditDialogVisible = false; });
    }

    protected virtual async Task DeleteEntityAsync(TListViewModel entity)
    {
        try
        {
            await CheckDeletePolicyAsync();
            await OnDeletingEntityAsync();
            await AppService.DeleteAsync(entity.Id);
            await OnDeletedEntityAsync();
        }
        catch (Exception ex)
        {
            await HandleErrorAsync(ex);
        }
    }

    protected virtual Task OnDeletingEntityAsync()
    {
        return Task.CompletedTask;
    }

    protected virtual async Task OnDeletedEntityAsync()
    {
        await DataGrid.ReloadServerData();
        await InvokeAsync(StateHasChanged);
        await Notify.Success(L[&quot;SuccessfullyDeleted&quot;]);
    }

    protected virtual string GetDeleteConfirmationMessage(TListViewModel entity)
    {
        return UiLocalizer[&quot;ItemWillBeDeletedMessage&quot;];
    }

    protected virtual async Task CheckCreatePolicyAsync()
    {
        await CheckPolicyAsync(CreatePolicyName);
    }

    protected virtual async Task CheckUpdatePolicyAsync()
    {
        await CheckPolicyAsync(UpdatePolicyName);
    }

    protected virtual async Task CheckDeletePolicyAsync()
    {
        await CheckPolicyAsync(DeletePolicyName);
    }

    /// &lt;summary&gt;
    /// Calls IAuthorizationService.CheckAsync for the given &lt;paramref name=&quot;policyName&quot;/&gt;.
    /// Throws &lt;see cref=&quot;AbpAuthorizationException&quot;/&gt; if given policy was not granted for the current user.
    ///
    /// Does nothing if &lt;paramref name=&quot;policyName&quot;/&gt; is null or empty.
    /// &lt;/summary&gt;
    /// &lt;param name=&quot;policyName&quot;&gt;A policy name to check&lt;/param&gt;
    protected virtual async Task CheckPolicyAsync([CanBeNull] string policyName)
    {
        if (string.IsNullOrEmpty(policyName))
        {
            return;
        }

        await AuthorizationService.CheckAsync(policyName);
    }

    protected virtual ValueTask SetBreadcrumbItemsAsync()
    {
        return ValueTask.CompletedTask;
    }

    protected virtual ValueTask SetEntityActionsAsync()
    {
        return ValueTask.CompletedTask;
    }

    protected virtual ValueTask SetTableColumnsAsync()
    {
        return ValueTask.CompletedTask;
    }

    protected virtual ValueTask SetToolbarItemsAsync()
    {
        return ValueTask.CompletedTask;
    }
}
</code></pre>
<p>This class will be used to replace <a href="https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.BlazoriseUI/AbpCrudPageBase.cs">AbpCrudPageBase</a>.</p>
<h2>15. Update <strong>Books</strong> CRUD Page</h2>
<p>Change type of <code>PublishDate</code> property in <code>Book</code>, <code>BookDto</code>, <code>CreateUpdateBookDto</code> from <code>DateTime</code> to <code>DateTime?</code></p>
<p>Update <code>Books.razor</code> with the following content:</p>
<pre><code class="language-razor">@page &quot;/books&quot;
@attribute [Authorize(BookStorePermissions.Books.Default)]
@using Acme.BookStore.Permissions
@using Microsoft.AspNetCore.Authorization
@using Volo.Abp.Application.Dtos
@using Acme.BookStore.Books
@using Acme.BookStore.Localization
@using Microsoft.Extensions.Localization
@using Volo.Abp.AspNetCore.Components.Web.BasicTheme.Components
@inherits MudCrudPageBase&lt;IBookAppService, BookDto, Guid, PagedAndSortedResultRequestDto, CreateUpdateBookDto&gt;
@inject AbpBlazorMessageLocalizerHelper&lt;BookStoreResource&gt; LH

&lt;MudDataGrid T=&quot;BookDto&quot;
             @ref=&quot;DataGrid&quot;
             Striped=&quot;true&quot;
             Hideable=&quot;true&quot;
             Elevation=&quot;8&quot;
             ServerData=&quot;LoadServerData&quot;&gt;
&lt;ToolBarContent&gt;
    &lt;MudText Typo=&quot;Typo.h5&quot;&gt;@L[&quot;Books&quot;]&lt;/MudText&gt;
    &lt;MudSpacer /&gt;
    &lt;MudButton Color=&quot;MudBlazor.Color.Primary&quot;
               Variant=&quot;Variant.Outlined&quot;
               Disabled=&quot;!HasCreatePermission&quot;
               OnClick=&quot;OpenCreateModalAsync&quot;&gt;
        @L[&quot;NewBook&quot;]
    &lt;/MudButton&gt;
&lt;/ToolBarContent&gt;
&lt;Columns&gt;
    &lt;MudBlazor.Column T=&quot;BookDto&quot;
                      Field=&quot;@nameof(BookDto.Id)&quot;
                      Hideable=&quot;false&quot;
                      Title=&quot;@L[&quot;Actions&quot;]&quot;&gt;
        &lt;CellTemplate&gt;
            @if (HasUpdatePermission)
            {
                &lt;MudIconButton Icon=&quot;fas fa-edit&quot; 
                               OnClick=&quot;@(async (_) =&gt; { await OpenEditModalAsync(context.Item); })&quot;
                               Size=&quot;MudBlazor.Size.Small&quot; /&gt;
            }
            @if (HasDeletePermission)
            {   
                &lt;MudIconButton Icon=&quot;fas fa-trash&quot; 
                               OnClick=&quot;@(async (_) =&gt; { await DeleteEntityAsync(context.Item);} )&quot;
                               Size=&quot;MudBlazor.Size.Small&quot; /&gt;
            }
        &lt;/CellTemplate&gt;
    &lt;/MudBlazor.Column&gt;
    &lt;MudBlazor.Column T=&quot;BookDto&quot;
                      Field=&quot;@nameof(BookDto.Name)&quot;
                      Hideable=&quot;false&quot;
                      Title=@L[&quot;Name&quot;] /&gt;
    &lt;MudBlazor.Column T=&quot;BookDto&quot;
                      Field=&quot;@nameof(BookDto.Type)&quot;
                      Title=@L[&quot;Type&quot;]&gt;
        &lt;CellTemplate&gt;
            @L[$&quot;Enum:BookType:{(int)context.Item.Type}&quot;]
        &lt;/CellTemplate&gt;
    &lt;/MudBlazor.Column&gt;
    &lt;MudBlazor.Column T=&quot;BookDto&quot;
                      Field=&quot;@nameof(BookDto.AuthorName)&quot;
                      Title=@L[&quot;AuthorName&quot;] /&gt;
    &lt;MudBlazor.Column T=&quot;BookDto&quot;
                      Field=&quot;@nameof(BookDto.PublishDate)&quot;
                      Title=@L[&quot;PublishDate&quot;]&gt;
        &lt;CellTemplate&gt;
            @if (@context.Item.PublishDate.HasValue)
                @context.Item.PublishDate.Value.ToShortDateString()
        &lt;/CellTemplate&gt;
    &lt;/MudBlazor.Column&gt;
    &lt;MudBlazor.Column T=&quot;BookDto&quot;
                      Field=&quot;@nameof(BookDto.Price)&quot;
                      Title=@L[&quot;Price&quot;] /&gt;
&lt;/Columns&gt;
&lt;/MudDataGrid&gt;

&lt;MudDialog @bind-IsVisible=&quot;CreateDialogVisible&quot; 
           Options=&quot;DialogOptions&quot;&gt;
    &lt;TitleContent&gt;
        &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@L[&quot;NewBook&quot;]&lt;/MudText&gt;
    &lt;/TitleContent&gt;
    &lt;DialogContent&gt;
        &lt;MudForm Model=&quot;@NewEntity&quot;
                 @ref=&quot;CreateForm&quot;&gt;
            &lt;MudSelect T=&quot;Guid&quot; 
                       @bind-Value=&quot;NewEntity.AuthorId&quot;
                       Label=@L[&quot;Author&quot;]&gt;
                &lt;MudSelectItem Value=&quot;@Guid.Empty&quot;&gt;
                    @L[&quot;PickAnAuthor&quot;]
                &lt;/MudSelectItem&gt;
                @foreach (var author in authorList)
                {
                    &lt;MudSelectItem Value=&quot;@author.Id&quot;&gt;
                        @author.Name
                    &lt;/MudSelectItem&gt;
                }
            &lt;/MudSelect&gt;
            &lt;br /&gt;
            &lt;MudTextField @bind-Value=&quot;@NewEntity.Name&quot; 
                          Label=@L[&quot;Name&quot;]
                          For=@(() =&gt; NewEntity.Name) /&gt;
            &lt;br /&gt;
            &lt;MudSelect T=&quot;BookType&quot; 
                       @bind-Value=&quot;NewEntity.Type&quot;
                       Label=@L[&quot;Type&quot;]&gt;
                @foreach (BookType bookTypeValue in Enum.GetValues(typeof(BookType)))
                {
                    &lt;MudSelectItem Value=&quot;@bookTypeValue&quot;&gt;
                        @L[$&quot;Enum:BookType:{(int)bookTypeValue}&quot;]
                    &lt;/MudSelectItem&gt;
                }
            &lt;/MudSelect&gt;
            &lt;br /&gt;
            &lt;MudDatePicker @bind-Date=&quot;@NewEntity.PublishDate&quot; 
                           Editable=&quot;true&quot;
                           Mask=&quot;@(new DateMask(&quot;dd.MM.yyyy&quot;))&quot; 
                           DateFormat=&quot;dd.MM.yyyy&quot;
                           Label=@L[&quot;PublishDate&quot;] /&gt;
            &lt;br /&gt;
            &lt;MudNumericField @bind-Value=&quot;@NewEntity.Price&quot; 
                             Label=@L[&quot;Price&quot;]
                             Min=0f
                             HideSpinButtons=&quot;true&quot;
                             For=@(() =&gt; NewEntity.Price) /&gt;
        &lt;/MudForm&gt;
    &lt;/DialogContent&gt;
    &lt;DialogActions&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                   OnClick=&quot;CloseCreateModalAsync&quot;&gt;
            @L[&quot;Cancel&quot;]
        &lt;/MudButton&gt;
        &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                   Color=&quot;MudBlazor.Color.Primary&quot; 
                   OnClick=&quot;CreateEntityAsync&quot;&gt;
            @L[&quot;Save&quot;]
        &lt;/MudButton&gt;
    &lt;/DialogActions&gt;
&lt;/MudDialog&gt;

&lt;MudDialog @bind-IsVisible=&quot;EditDialogVisible&quot;
           Options=&quot;DialogOptions&quot;&gt;
    &lt;TitleContent&gt;
        &lt;MudText Typo=&quot;Typo.h6&quot;&gt;@EditingEntity.Name&lt;/MudText&gt;
    &lt;/TitleContent&gt;
    &lt;DialogContent&gt;
        &lt;MudForm Model=&quot;@EditingEntity&quot;
                 @ref=&quot;EditForm&quot;&gt;
            &lt;MudSelect T=&quot;Guid&quot; 
                       @bind-Value=&quot;EditingEntity.AuthorId&quot;
                       Label=@L[&quot;Author&quot;]&gt;
                &lt;MudSelectItem Value=&quot;@Guid.Empty&quot;&gt;
                    @L[&quot;PickAnAuthor&quot;]
                &lt;/MudSelectItem&gt;
                @foreach (var author in authorList)
                {
                    &lt;MudSelectItem Value=&quot;@author.Id&quot;&gt;
                        @author.Name
                    &lt;/MudSelectItem&gt;
                }
            &lt;/MudSelect&gt;
            &lt;br /&gt;
            &lt;MudTextField @bind-Value=&quot;@EditingEntity.Name&quot; 
                          Label=@L[&quot;Name&quot;]
                          For=@(() =&gt; EditingEntity.Name) /&gt;
            &lt;br /&gt;
            &lt;MudSelect T=&quot;BookType&quot; 
                       @bind-Value=&quot;EditingEntity.Type&quot;
                       Label=@L[&quot;Type&quot;]&gt;
                @foreach (BookType bookTypeValue in Enum.GetValues(typeof(BookType)))
                {
                    &lt;MudSelectItem Value=&quot;@bookTypeValue&quot;&gt;
                        @L[$&quot;Enum:BookType:{(int)bookTypeValue}&quot;]
                    &lt;/MudSelectItem&gt;
                }
            &lt;/MudSelect&gt;
            &lt;br /&gt;
            &lt;MudDatePicker @bind-Date=&quot;@EditingEntity.PublishDate&quot; 
                           Editable=&quot;true&quot;
                           Mask=&quot;@(new DateMask(&quot;dd.MM.yyyy&quot;))&quot; 
                           DateFormat=&quot;dd.MM.yyyy&quot;
                           Label=@L[&quot;PublishDate&quot;] /&gt;
            &lt;br /&gt;
            &lt;MudNumericField @bind-Value=&quot;@EditingEntity.Price&quot; 
                             Label=@L[&quot;Price&quot;]
                             Min=0f
                             HideSpinButtons=&quot;true&quot;
                             For=@(() =&gt; EditingEntity.Price) /&gt;
        &lt;/MudForm&gt;
    &lt;/DialogContent&gt;
    &lt;DialogActions&gt;
        &lt;MudButton Color=&quot;MudBlazor.Color.Secondary&quot; 
                   OnClick=&quot;CloseEditModalAsync&quot;&gt;
            @L[&quot;Cancel&quot;]
        &lt;/MudButton&gt;
        &lt;MudButton Variant=&quot;Variant.Filled&quot; 
                   Color=&quot;MudBlazor.Color.Primary&quot; 
                   OnClick=&quot;UpdateEntityAsync&quot;&gt;
            @L[&quot;Save&quot;]
        &lt;/MudButton&gt;
    &lt;/DialogActions&gt;
&lt;/MudDialog&gt;

@code
{
    //ADDED A NEW FIELD
    IReadOnlyList&lt;AuthorLookupDto&gt; authorList = Array.Empty&lt;AuthorLookupDto&gt;();

    public Books() // Constructor
    {
        LocalizationResource = typeof(BookStoreResource);

        CreatePolicyName = BookStorePermissions.Books.Create;
        UpdatePolicyName = BookStorePermissions.Books.Edit;
        DeletePolicyName = BookStorePermissions.Books.Delete;
    }

    //GET AUTHORS ON INITIALIZATION
    protected override async Task OnInitializedAsync()
    {
        await base.OnInitializedAsync();
        authorList = (await AppService.GetAuthorLookupAsync()).Items;
    }
}
</code></pre>
<h2>Next</h2>
<p><a href="https://github.com/yellow-dragon-cloud/AbpMudBlazorFinal">MudBlazor Theme in ABP Blazor WebAssembly FINAL</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/c67cb5c7-7a08-85e9-c2a7-3a02daa528e8" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/c67cb5c7-7a08-85e9-c2a7-3a02daa528e8" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-part-3-c8hwx00l</guid>
      <link>https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-part-3-c8hwx00l</link>
      <a10:author>
        <a10:name>a-urel</a10:name>
        <a10:uri>https://abp.io/community/members/a-urel</a10:uri>
      </a10:author>
      <category>blazor-wasm</category>
      <category>MudBlazor</category>
      <title>MudBlazor Theme in ABP Blazor WebAssembly Part 3</title>
      <description>In this part, I will show you how to replace the built-in messaging service to show MudBlazor message boxes.</description>
      <pubDate>Mon, 07 Mar 2022 20:45:06 Z</pubDate>
      <a10:updated>2026-03-08T05:58:27Z</a10:updated>
      <content:encoded><![CDATA[<h1>MudBlazor Theme in ABP Blazor WebAssembly PART 3</h1>
<h2>Introduction</h2>
<p>In this part, I will show you how to replace the built-in messaging service to show <a href="https://www.mudblazor.com/">MudBlazor</a> <a href="https://www.mudblazor.com/components/messagebox#api">message boxes</a>.</p>
<h2>8. Make Sure You Have Completed PART 1 &amp; Part 2</h2>
<p>This project is built on top of <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor">MudBlazor Theme in ABP Blazor WebAssembly PART 1</a> and <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor2">MudBlazor Theme in ABP Blazor WebAssembly PART 2</a>. Before continuing, you need to complete these parts in order, if you haven't already.</p>
<h2>9. Add <a href="https://www.mudblazor.com/components/messagebox#api">MudBlazor MessageBox</a> Support to MainLayout</h2>
<p>Open <code>MainLayout.razor</code> and replace it with the code below:</p>
<pre><code class="language-razor">@inherits LayoutComponentBase

&lt;MudThemeProvider /&gt;
&lt;MudSnackbarProvider /&gt;
&lt;MudDialogProvider /&gt;

&lt;MudLayout&gt;
    &lt;MudAppBar Elevation=&quot;8&quot;&gt;
        &lt;MudIconButton Icon=&quot;@Icons.Material.Filled.Menu&quot; Color=&quot;MudBlazor.Color.Inherit&quot; Edge=&quot;Edge.Start&quot; 
                       OnClick=&quot;@((e) =&gt; DrawerToggle())&quot; /&gt;
        &lt;Branding /&gt;
        &lt;MudSpacer /&gt;
        &lt;NavToolbar /&gt;
    &lt;/MudAppBar&gt;
    &lt;MudDrawer @bind-Open=&quot;_drawerOpen&quot; ClipMode=&quot;DrawerClipMode.Always&quot; Elevation=&quot;8&quot;&gt;
        &lt;NavMenu /&gt;
    &lt;/MudDrawer&gt;
    &lt;MudMainContent&gt;
        &lt;MudContainer MaxWidth=&quot;MaxWidth.False&quot; Class=&quot;mt-4&quot;&gt;
            &lt;PageAlert /&gt;
            @Body
            &lt;UiPageProgress /&gt;
        &lt;/MudContainer&gt;
    &lt;/MudMainContent&gt;
&lt;/MudLayout&gt;

@code 
{
    private bool _drawerOpen = true;

    private void DrawerToggle()
    {
        _drawerOpen = !_drawerOpen;
    }
}
</code></pre>
<h2>10. Replace <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Message">Message Service</a></h2>
<p>In <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme/Services</code> folder, create a new <code>MudBlazorUiMessageService.cs</code> file with the following code:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using Localization.Resources.AbpUi;
using Microsoft.Extensions.Localization;
using MudBlazor;
using Volo.Abp.AspNetCore.Components.Messages;
using Volo.Abp.DependencyInjection;

namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Services;

[Dependency(ReplaceServices = true)]
public class MudBlazorUiMessageService : IUiMessageService, IScopedDependency
{
    private readonly IDialogService _dialogService;
    private readonly IStringLocalizer&lt;AbpUiResource&gt; _localizer;

    public MudBlazorUiMessageService(IDialogService dialogService, IStringLocalizer&lt;AbpUiResource&gt; localizer)
    {
        _dialogService = dialogService;
        _localizer = localizer;
    }

    public async Task&lt;bool&gt; Confirm(string message, string title = null, Action&lt;UiMessageOptions&gt; options = null)
    {
        var result = await _dialogService.ShowMessageBox(
            title, message, yesText: _localizer[&quot;Yes&quot;], noText: _localizer[&quot;No&quot;]);
        return result ?? false;
    }

    public Task Error(string message, string title = null, Action&lt;UiMessageOptions&gt; options = null)
    {
        _dialogService.ShowMessageBox(title, message, yesText: _localizer[&quot;Ok&quot;]);
        return Task.CompletedTask;
    }

    public Task Info(string message, string title = null, Action&lt;UiMessageOptions&gt; options = null)
    {
        _dialogService.ShowMessageBox(title, message, yesText: _localizer[&quot;Ok&quot;]);
        return Task.CompletedTask;
    }

    public Task Success(string message, string title = null, Action&lt;UiMessageOptions&gt; options = null)
    {
        _dialogService.ShowMessageBox(title, message, yesText: _localizer[&quot;Ok&quot;]);
        return Task.CompletedTask;
    }

    public Task Warn(string message, string title = null, Action&lt;UiMessageOptions&gt; options = null)
    {
        _dialogService.ShowMessageBox(title, message, yesText: _localizer[&quot;Ok&quot;]);
        return Task.CompletedTask;
    }
}
</code></pre>
<p>This code replaces <code>IUiMessageService</code> service. See <a href="https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Overriding-Services">Overriding Services</a> for more information.</p>
<p>Finally, edit <code>Index.razor</code> to test new message boxes:</p>
<pre><code class="language-razor">@page &quot;/&quot;
@using Volo.Abp.AspNetCore.Components.Messages
@using Volo.Abp.AspNetCore.Components.Notifications
@inherits BookStoreComponentBase
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject IUiNotificationService NotificationService
@inject IUiMessageService MessageService

&lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;p-5 text-center&quot;&gt;
        &lt;Button onclick=&quot;@(async () =&gt; { await NotificationService.Success(&quot;Hello, World!&quot;); await NotificationService.Warn(&quot;Something went wrong!&quot;); })&quot;&gt;
            Show Notifications!
        &lt;/Button&gt;
        &lt;hr /&gt;
        &lt;Button onclick=&quot;@(() =&gt; { MessageService.Info(&quot;Hello, World!&quot;); })&quot;&gt;
            Show Info!
        &lt;/Button&gt;
        &lt;br /&gt;
        &lt;Button onclick=&quot;@(() =&gt; { throw new Exception(); })&quot;&gt;
            Show Error!
        &lt;/Button&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h2>The Result</h2>
<p><img src="https://raw.githubusercontent.com/yellow-dragon-cloud/AbpMudBlazor3/main/images/screenshot3.png" alt="image" /></p>
<h2>Next</h2>
<p><a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor4">MudBlazor Theme in ABP Blazor WebAssembly PART 4</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/18dbd19c-5997-63b9-96e4-3a02784dbe1f" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/18dbd19c-5997-63b9-96e4-3a02784dbe1f" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-part-2-tkvrvyvm</guid>
      <link>https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-part-2-tkvrvyvm</link>
      <a10:author>
        <a10:name>a-urel</a10:name>
        <a10:uri>https://abp.io/community/members/a-urel</a10:uri>
      </a10:author>
      <category>blazor-wasm</category>
      <category>MudBlazor</category>
      <title>MudBlazor Theme in ABP Blazor WebAssembly PART 2</title>
      <description>This sample ABP Blazor WebAssembly project shows how to replace built-in Notification service to display notifications with MudBlazor's Snackbar component.</description>
      <pubDate>Thu, 24 Feb 2022 04:53:17 Z</pubDate>
      <a10:updated>2026-03-08T09:50:40Z</a10:updated>
      <content:encoded><![CDATA[<h1>MudBlazor Theme in ABP Blazor WebAssembly PART 2</h1>
<h2>Introduction</h2>
<p>This sample <a href="https://abp.io/">ABP</a> Blazor WebAssembly project shows how to replace built-in <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Notification">Notification</a> service to display notifications with <a href="https://www.mudblazor.com/">MudBlazor</a>'s <a href="https://www.mudblazor.com/components/snackbar#api">Snackbar</a> component. The source code is <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor2/">avallable on GitHub</a>.</p>
<h2>5. Make Sure You Have Completed PART 1</h2>
<p>This project is built on top of <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor/">MudBlazor Theme in ABP Blazor WebAssembly PART 1</a>. Therefore, you will first need to complete the steps shown in PART 1 to continue following the steps listed here.</p>
<h2>6. Add <a href="https://www.mudblazor.com/components/snackbar#api">MudBlazor Snackbar</a> Support To MainLayout</h2>
<p>Open <code>MainLayout.razor</code>, add <code>&lt;MudSnackbarProvider /&gt;</code> and remove <code>&lt;UiNotificationAlert /&gt;</code>. The final content of the file should look like this:</p>
<pre><code class="language-razor">@inherits LayoutComponentBase

&lt;MudThemeProvider /&gt;
&lt;MudSnackbarProvider /&gt;

&lt;MudLayout&gt;
    &lt;MudAppBar Elevation=&quot;8&quot;&gt;
        &lt;MudIconButton Icon=&quot;@Icons.Material.Filled.Menu&quot; Color=&quot;MudBlazor.Color.Inherit&quot; Edge=&quot;Edge.Start&quot; 
                       OnClick=&quot;@((e) =&gt; DrawerToggle())&quot; /&gt;
        &lt;Branding /&gt;
        &lt;MudSpacer /&gt;
        &lt;NavToolbar /&gt;
    &lt;/MudAppBar&gt;
    &lt;MudDrawer @bind-Open=&quot;_drawerOpen&quot; ClipMode=&quot;DrawerClipMode.Always&quot; Elevation=&quot;8&quot;&gt;
        &lt;NavMenu /&gt;
    &lt;/MudDrawer&gt;
    &lt;MudMainContent&gt;
        &lt;MudContainer MaxWidth=&quot;MaxWidth.False&quot; Class=&quot;mt-4&quot;&gt;
            &lt;PageAlert /&gt;
            @Body
            &lt;UiMessageAlert /&gt;
            &lt;UiPageProgress /&gt;
        &lt;/MudContainer&gt;
    &lt;/MudMainContent&gt;
&lt;/MudLayout&gt;

@code 
{
    private bool _drawerOpen = true;

    private void DrawerToggle()
    {
        _drawerOpen = !_drawerOpen;
    }
}
</code></pre>
<h2>7. Replace <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Notification">Notification Service</a></h2>
<p>In <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme</code> project, create a folder named <code>Services</code>. Create <code>MudBlazorUiNotificationService.cs</code> file in this folder, and add the following content:</p>
<pre><code class="language-csharp">using System;
using System.Threading.Tasks;
using MudBlazor;
using Volo.Abp.AspNetCore.Components.Notifications;
using Volo.Abp.DependencyInjection;

namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme.Services;

[Dependency(ReplaceServices = true)]
public class MudBlazorUiNotificationService : IUiNotificationService, IScopedDependency
{
    private readonly ISnackbar _snackbar;

    public MudBlazorUiNotificationService(ISnackbar snackbar)
    {
        _snackbar = snackbar;
    }

    public Task Error(string message, string title = null, Action&lt;UiNotificationOptions&gt; options = null)
    {
        _snackbar.Add(message, Severity.Error);
        return Task.CompletedTask;
    }

    public Task Info(string message, string title = null, Action&lt;UiNotificationOptions&gt; options = null)
    {
        _snackbar.Add(message, Severity.Info);
        return Task.CompletedTask;
    }

    public Task Success(string message, string title = null, Action&lt;UiNotificationOptions&gt; options = null)
    {
        _snackbar.Add(message, Severity.Success);
        return Task.CompletedTask;
    }

    public Task Warn(string message, string title = null, Action&lt;UiNotificationOptions&gt; options = null)
    {
        _snackbar.Add(message, Severity.Warning);
        return Task.CompletedTask;
    }
}
</code></pre>
<p>The code shown above automatically replaces the built-in <code>IUiNotificationService</code> service. To learn more about this mechanism <a href="https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Overriding-Services">see Overriding Services</a>.</p>
<p>Now, modify <code>Index.razor</code> file to test MudBlazor style notifications:</p>
<pre><code class="language-razor">@page &quot;/&quot;
@using Volo.Abp.AspNetCore.Components.Notifications
@inherits BookStoreComponentBase
@inject AuthenticationStateProvider AuthenticationStateProvider
@inject IUiNotificationService NotificationService

&lt;div class=&quot;container&quot;&gt;
    &lt;div class=&quot;p-5 text-center&quot;&gt;
        &lt;Button onclick=&quot;@(async () =&gt; { await NotificationService.Success(&quot;Hello, World!&quot;); await NotificationService.Warn(&quot;Something went wrong!&quot;); })&quot;&gt;
            Show Notifications!
        &lt;/Button&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre>
<h2>The Result</h2>
<p><img src="https://raw.githubusercontent.com/yellow-dragon-cloud/AbpMudBlazor2/main/images/screenshot2.png" alt="image" /></p>
<h2>Next</h2>
<p><a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor3">MudBlazor Theme in ABP Blazor WebAssembly PART 3</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/304c9fd0-5f07-2c1f-a70e-3a023c406151" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/304c9fd0-5f07-2c1f-a70e-3a023c406151" medium="image" />
    </item>
    <item>
      <guid isPermaLink="true">https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-ae23zz17</guid>
      <link>https://abp.io/community/posts/mudblazor-theme-in-abp-blazor-webassembly-ae23zz17</link>
      <a10:author>
        <a10:name>a-urel</a10:name>
        <a10:uri>https://abp.io/community/members/a-urel</a10:uri>
      </a10:author>
      <category>blazor-wasm</category>
      <category>MudBlazor</category>
      <title>MudBlazor Theme in ABP Blazor WebAssembly</title>
      <description>This sample demonstrates how you can use MudBlazor layouts in your ABP Blazor WebAssembly applications.</description>
      <pubDate>Wed, 16 Feb 2022 16:32:47 Z</pubDate>
      <a10:updated>2026-03-08T12:46:02Z</a10:updated>
      <content:encoded><![CDATA[<h1>MudBlazor Theme in ABP Blazor WebAssembly PART 1</h1>
<h2>Introduction</h2>
<p>It is quite easy to customize default template and layout of an <a href="https://abp.io/">ABP</a> Blazor application. This sample demonstrates how you can use MudBlazor layouts in your ABP Blazor WebAssembly applications. The source code is <a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor">available on GitHub</a></p>
<h2>What is MudBlazor?</h2>
<p><a href="https://www.mudblazor.com/">MudBlazor</a> is a Blazor component library trusted by thousands of users, from hobbyists to enterprises.</p>
<h2>1. Create a new ABP Blazor WebAssembly application</h2>
<p>Install or update the ABP CLI:</p>
<pre><code class="language-bash">dotnet tool install -g Volo.Abp.Cli || dotnet tool update -g Volo.Abp.Cli
</code></pre>
<p>Create a new ABP Blazor WebAssembly application:</p>
<pre><code class="language-bash">abp new Acme.BookStore -u blazor -d mongodb
</code></pre>
<h2>2. Add packages to your solution</h2>
<p>Copy the source code of <a href="https://docs.abp.io/en/abp/latest/UI/Blazor/Basic-Theme">Basic Theme</a> to your solution:</p>
<pre><code class="language-bash">abp add-package Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme --with-source-code --add-to-solution-file
</code></pre>
<p>Then, navigate to downloaded <code>Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme</code> project directory and run:</p>
<pre><code class="language-bash">abp add-package Volo.Abp.AspNetCore.Components.Web.BasicTheme --with-source-code --add-to-solution-file
</code></pre>
<p>To add downloaded projects to source control, open <code>.gitignore</code> file and add this line:</p>
<pre><code class="language-gitignore">!**/packages/*Theme*
</code></pre>
<h2>3. Add MudBlazor</h2>
<p>Navigate to downloaded <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme</code> project directory and install MudBlazor:</p>
<pre><code class="language-bash">dotnet add package MudBlazor
</code></pre>
<p>In <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme</code> project, open <code>AbpAspNetCoreComponentsWebBasicThemeModule.cs</code> file, and replace its content with the following code:</p>
<pre><code class="language-csharp">using MudBlazor.Services;
using Volo.Abp.AspNetCore.Components.Web.Theming;
using Volo.Abp.Modularity;

namespace Volo.Abp.AspNetCore.Components.Web.BasicTheme;

[DependsOn(
    typeof(AbpAspNetCoreComponentsWebThemingModule)
)]
public class AbpAspNetCoreComponentsWebBasicThemeModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        base.ConfigureServices(context);
        context.Services.AddMudServices();
    }
}
</code></pre>
<p>And in <code>Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme</code> project, open <code>BasicThemeBundleContributor.cs</code> file, and replace its content with the following code:</p>
<pre><code class="language-csharp">using Volo.Abp.Bundling;

namespace Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme;

public class BasicThemeBundleContributor : IBundleContributor
{
    public void AddScripts(BundleContext context)
    {
        context.Add(&quot;_content/MudBlazor/MudBlazor.min.js&quot;);
    }

    public void AddStyles(BundleContext context)
    {
        context.Add(&quot;_content/Volo.Abp.AspNetCore.Components.Web.BasicTheme/libs/abp/css/theme.css&quot;);

        context.Add(&quot;https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap&quot;);
        context.Add(&quot;_content/MudBlazor/MudBlazor.min.css&quot;);
    }
}
</code></pre>
<p>Add the following to your HTML head section of <code>index.html</code> file in <code>Acme.BookStore.Blazor</code> project:</p>
<pre><code class="language-html">&lt;link href=&quot;https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;display=swap&quot; rel=&quot;stylesheet&quot; /&gt;
&lt;link href=&quot;_content/MudBlazor/MudBlazor.min.css&quot; rel=&quot;stylesheet&quot; /&gt;
</code></pre>
<p>In the same file but located in the end of it add the MudBlazor js file, it should be in the same location as the default blazor script:</p>
<pre><code class="language-html">&lt;script src=&quot;_content/MudBlazor/MudBlazor.min.js&quot;&gt;&lt;/script&gt;
</code></pre>
<p>Add this line to <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/_Imports.razor</code> and <code>Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/_Imports.razor</code> files:</p>
<pre><code class="language-razor">@using MudBlazor
</code></pre>
<h2>4. Customize Basic Theme</h2>
<p>Open <code>Volo.Abp.AspNetCore.Components.Web.BasicTheme/Themes/Basic/</code> folder.</p>
<p>Replace <code>Branding.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@using Volo.Abp.Ui.Branding
@inject IBrandingProvider BrandingProvider

&lt;MudText Typo=&quot;Typo.h5&quot; Class=&quot;ml-3&quot;&gt;
    @BrandingProvider.AppName
&lt;/MudText&gt;
</code></pre>
<p>Replace <code>FirstLevelNavMenuItem.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@using Volo.Abp.UI.Navigation

@{
    var elementId = MenuItem.ElementId ?? &quot;MenuItem_&quot; + MenuItem.Name.Replace(&quot;.&quot;, &quot;_&quot;);
    var cssClass = string.IsNullOrEmpty(MenuItem.CssClass) ? string.Empty : MenuItem.CssClass;
    var disabled = MenuItem.IsDisabled ? &quot;disabled&quot; : string.Empty;
    var url = MenuItem.Url == null ? &quot;#&quot; : MenuItem.Url.TrimStart('/', '~');
}

@if (MenuItem.IsLeaf)
{
    if (MenuItem.Url is not null)
    {
        &lt;MudNavLink Icon=&quot;@MenuItem.Icon&quot; Href=&quot;@url&quot; Target=&quot;@MenuItem.Target&quot; Match=&quot;NavLinkMatch.All&quot;&gt;
            @MenuItem.DisplayName
        &lt;/MudNavLink&gt;
    }
}
else
{
    &lt;MudNavGroup Icon=&quot;@MenuItem.Icon&quot; Title=&quot;@MenuItem.DisplayName&quot;&gt;
        @foreach (var childMenuItem in MenuItem.Items.OrderBy(i =&gt; i.Order))
        {
            &lt;SecondLevelNavMenuItem MenuItem=&quot;@childMenuItem&quot;/&gt;
        }
    &lt;/MudNavGroup&gt;
}
</code></pre>
<p>Replace <code>SecondLevelNavMenuItem.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@using Volo.Abp.UI.Navigation

@{
    var elementId = MenuItem.ElementId ?? &quot;MenuItem_&quot; + MenuItem.Name.Replace(&quot;.&quot;, &quot;_&quot;);
    var cssClass = string.IsNullOrEmpty(MenuItem.CssClass) ? string.Empty : MenuItem.CssClass;
    var disabled = MenuItem.IsDisabled ? &quot;disabled&quot; : string.Empty;
    var url = MenuItem.Url == null ? &quot;#&quot; : MenuItem.Url.TrimStart('/', '~');
}

@if (MenuItem.IsLeaf)
{
    if (MenuItem.Url is not null)
    {
        &lt;MudNavLink Icon=&quot;@MenuItem.Icon&quot; Href=&quot;@url&quot; Target=&quot;@MenuItem.Target&quot;&gt;
            @MenuItem.DisplayName
        &lt;/MudNavLink&gt;
    }
}
else
{
    &lt;MudNavGroup Icon=&quot;@MenuItem.Icon&quot; Title=&quot;@MenuItem.DisplayName&quot;&gt;
        @foreach (var childMenuItem in MenuItem.Items.OrderBy(i =&gt; i.Order))
        {
            &lt;SecondLevelNavMenuItem MenuItem=&quot;@childMenuItem&quot;/&gt;
        }
    &lt;/MudNavGroup&gt;
}
</code></pre>
<p>Replace <code>NavToolbar.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@foreach (var render in ToolbarItemRenders)
{
    @render
}
</code></pre>
<p>Replace <code>MainLayout.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@inherits LayoutComponentBase

&lt;MudThemeProvider /&gt;

&lt;MudLayout&gt;
    &lt;MudAppBar Elevation=&quot;8&quot;&gt;
        &lt;MudIconButton Icon=&quot;@Icons.Material.Filled.Menu&quot; Color=&quot;MudBlazor.Color.Inherit&quot; Edge=&quot;Edge.Start&quot; 
                       OnClick=&quot;@((e) =&gt; DrawerToggle())&quot; /&gt;
        &lt;Branding /&gt;
        &lt;MudSpacer /&gt;
        &lt;NavToolbar /&gt;
    &lt;/MudAppBar&gt;
    &lt;MudDrawer @bind-Open=&quot;_drawerOpen&quot; ClipMode=&quot;DrawerClipMode.Always&quot; Elevation=&quot;8&quot;&gt;
        &lt;NavMenu /&gt;
    &lt;/MudDrawer&gt;
    &lt;MudMainContent&gt;
        &lt;MudContainer MaxWidth=&quot;MaxWidth.False&quot; Class=&quot;mt-4&quot;&gt;
            &lt;PageAlert /&gt;
            @Body
            &lt;UiMessageAlert /&gt;
            &lt;UiNotificationAlert /&gt;
            &lt;UiPageProgress /&gt;
        &lt;/MudContainer&gt;
    &lt;/MudMainContent&gt;
&lt;/MudLayout&gt;

@code 
{
    private bool _drawerOpen = true;

    private void DrawerToggle()
    {
        _drawerOpen = !_drawerOpen;
    }
}
</code></pre>
<p>You can use a different layout. See other <a href="https://www.mudblazor.com/getting-started/wireframes#main-layouts">main layout options</a>.</p>
<p>Now open <code>Volo.Abp.AspNetCore.Components.WebAssembly.BasicTheme/Themes/Basic/</code> folder.</p>
<p>Replace <code>LanguageSwitch.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@using Volo.Abp.Localization
@using System.Globalization
@using System.Collections.Immutable
@inject ILanguageProvider LanguageProvider
@inject IJSRuntime JsRuntime

@if (_otherLanguages is not null &amp;&amp; _otherLanguages.Any())
{
    &lt;MudMenu Color=&quot;MudBlazor.Color.Inherit&quot; Direction=&quot;MudBlazor.Direction.Left&quot; OffsetX=&quot;true&quot; Dense=&quot;true&quot;&gt;
        &lt;ActivatorContent&gt;
            &lt;MudChip Color=&quot;MudBlazor.Color.Primary&quot;&gt;
                @_currentLanguage.DisplayName
            &lt;/MudChip&gt;
        &lt;/ActivatorContent&gt;
        &lt;ChildContent&gt;
            @foreach (var language in _otherLanguages)
            {
                &lt;MudMenuItem OnClick=&quot;@(async () =&gt; await ChangeLanguageAsync(language))&quot;&gt;
                    @language.DisplayName
                &lt;/MudMenuItem&gt;
            }
        &lt;/ChildContent&gt;
    &lt;/MudMenu&gt;
}

@code {
    private IReadOnlyList&lt;LanguageInfo&gt; _otherLanguages;
    private LanguageInfo _currentLanguage;

    protected override async Task OnInitializedAsync()
    {
        var selectedLanguageName = await JsRuntime.InvokeAsync&lt;string&gt;(
            &quot;localStorage.getItem&quot;,
            &quot;Abp.SelectedLanguage&quot;);

        _otherLanguages = await LanguageProvider.GetLanguagesAsync();

        if (!_otherLanguages.Any()) return;

        if (!selectedLanguageName.IsNullOrWhiteSpace())
            _currentLanguage = _otherLanguages.FirstOrDefault(l =&gt; l.UiCultureName == selectedLanguageName);

        _currentLanguage ??= _otherLanguages.FirstOrDefault(l =&gt; l.UiCultureName == CultureInfo.CurrentUICulture.Name);
        _currentLanguage ??= _otherLanguages.FirstOrDefault();

        _otherLanguages = _otherLanguages.Where(l =&gt; l != _currentLanguage).ToImmutableList();
    }

    private async Task ChangeLanguageAsync(LanguageInfo language)
    {
        await JsRuntime.InvokeVoidAsync(
            &quot;localStorage.setItem&quot;,
            &quot;Abp.SelectedLanguage&quot;, language.UiCultureName);

        await JsRuntime.InvokeVoidAsync(&quot;location.reload&quot;);
    }
}
</code></pre>
<p>Replace <code>LoginDisplay.razor</code> file's content with the following code:</p>
<pre><code class="language-razor">@using Microsoft.Extensions.Localization
@using Volo.Abp.Users
@using Volo.Abp.MultiTenancy
@using global::Localization.Resources.AbpUi
@inherits AbpComponentBase
@inject ICurrentUser CurrentUser
@inject ICurrentTenant CurrentTenant
@inject IJSRuntime JsRuntime
@inject NavigationManager Navigation
@inject IStringLocalizer&lt;AbpUiResource&gt; UiLocalizer

&lt;AuthorizeView&gt;
    &lt;Authorized&gt;
        &lt;MudMenu Color=&quot;MudBlazor.Color.Inherit&quot; Direction=&quot;MudBlazor.Direction.Left&quot; OffsetX=&quot;true&quot; Dense=&quot;true&quot;&gt;
            &lt;ActivatorContent&gt;
                &lt;MudChip Color=&quot;MudBlazor.Color.Primary&quot;&gt;
                    @CurrentUser.Name
                &lt;/MudChip&gt;
            &lt;/ActivatorContent&gt;
            &lt;ChildContent&gt;
                @if (Menu is not null &amp;&amp; Menu.Items.Any())
                {
                    @foreach (var menuItem in Menu.Items)
                    {
                        &lt;MudListItem OnClick=&quot;@(async () =&gt; await NavigateToAsync(menuItem.Url, menuItem.Target))&quot;&gt;
                            @menuItem.DisplayName
                        &lt;/MudListItem&gt;
                    }
                    &lt;MudDivider /&gt;
                }
                &lt;MudListItem Icon=&quot;@Icons.Material.Outlined.Login&quot; OnClick=&quot;BeginSignOut&quot;&gt;
                    @UiLocalizer[&quot;Logout&quot;]
                &lt;/MudListItem&gt;
            &lt;/ChildContent&gt;
        &lt;/MudMenu&gt;
    &lt;/Authorized&gt;
    &lt;NotAuthorized&gt;
        &lt;MudLink Color=&quot;MudBlazor.Color.Inherit&quot; Href=&quot;authentication/login&quot;&gt;
            &lt;MudChip Color=&quot;MudBlazor.Color.Primary&quot;&gt;
                @UiLocalizer[&quot;Login&quot;]
            &lt;/MudChip&gt;
        &lt;/MudLink&gt;
    &lt;/NotAuthorized&gt;
&lt;/AuthorizeView&gt;
</code></pre>
<h2>The Result</h2>
<p><img src="https://raw.githubusercontent.com/yellow-dragon-cloud/AbpMudBlazor/main/images/screenshot.png" alt="image" /></p>
<h2>Next</h2>
<p><a href="https://github.com/yellow-dragon-cloud/AbpMudBlazor2">MudBlazor Theme in ABP Blazor WebAssembly PART 2</a></p>
]]></content:encoded>
      <media:thumbnail url="https://abp.io/api/posts/cover-picture-source/eb41f1f5-a630-194a-0d1f-3a02158dea51" />
      <media:content url="https://abp.io/api/posts/cover-picture-source/eb41f1f5-a630-194a-0d1f-3a02158dea51" medium="image" />
    </item>
  </channel>
</rss>