buildcomplete
buildcomplete

Reputation: 552

Making a Custom Blazor component

I am starting with some Blazor fun, and one of the first things I am trying is to wrap my menu items to custom compoenents to make the navigation more readable.

I try something along the line:

File: Components\MenuItem.razor

<AuthorizeView Roles="@Roles">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="@Link">
            <span class="oi oi-task" aria-hidden="true"></span> @Text
        </NavLink>
    </li>
</AuthorizeView>
@code {
    public string Link { get; set; }
    public string Text { get; set; }
    public string Roles { get; set; }
}

But if I use the component instead of identical content in the navigation, nothing is loaded when i run the application.

in my navmenu, adding the following

<VM.Web.Components.MenuItem Text="Approve user requests" Link="/users/pending-approval" Roles="ADMIN, CREW" />

stops the page from loading (I don't see any errors) but the following directly in the navmenu works

<AuthorizeView Roles="ADMIN, CREW">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="/users/pending-approval">
            <span class="oi oi-task" aria-hidden="true"></span> Approve user requests
        </NavLink>
    </li>
</AuthorizeView>

Update, The issue was that I was missing the [Parameter] decoration, after that it worked

The final Component code looks like this

<AuthorizeView Roles="@Roles">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="@Link">
            <span class="@SpanClasses" aria-hidden="true"></span> @Text
        </NavLink>
    </li>
</AuthorizeView>
@code {
    [Parameter]
    public string Link { get; set; }

    [Parameter]
    public string Text { get; set; }

    [Parameter]
    public string Roles { get; set; }

    [Parameter]
    public string SpanClasses { get; set; }
}

For reference, The authentication module was implemented by another programmer and works :), it is configured like this

builder.Services
    .AddOidcAuthentication(options =>
    {
        builder.Configuration.Bind("oidc", options.ProviderOptions);
        options.UserOptions.RoleClaim = "role";
        options.AuthenticationPaths.LogInFailedPath = "/";
        options.AuthenticationPaths.LogOutSucceededPath = "/";
        options.AuthenticationPaths.LogOutCallbackPath = "/authentication/logout-callback";
    })
    .AddAccountClaimsPrincipalFactory<ArrayClaimsPrincipalFactory<RemoteUserAccount>>();

AuthorityConnection = builder.Configuration.GetSection("oidc:Authority").Value;

Upvotes: 1

Views: 581

Answers (1)

Brian Parker
Brian Parker

Reputation: 14623

directly in the navmenu works

<AuthorizeView Roles="ADMIN, CREW">

Tells me your roles are being passed to WebAssembly

I found this useful when passing menu items as data. I needed to cater for unauthorized, authorized and I added roles.

The Claims factory that Enet has provided is also needed if any of the users have more than one role as they arrive in comma separated format.

OptionalRolesAuthorizeView.razor

@if (string.IsNullOrWhiteSpace(Roles) && RequireAuthentication == false)
{
    @ChildContent
}
else
{
    <AuthorizeView Roles="@Roles">
        @ChildContent
    </AuthorizeView>
}
@code {
    [Parameter]
    public bool RequireAuthentication { get; set; }

    [Parameter]
    public string Roles { get; set; }

    [Parameter]
    public RenderFragment ChildContent { get; set; }
}

MenuItemView.razor

<OptionalRolesAuthorizeView RequireAuthentication="@Model.RequireAuthentication" Roles="@Model.Roles">
    <li class="nav-item px-3">
        <NavLink class="nav-link" href="@Model.Href" Match="@Model.Match">
            <span class="@Model.IconClass" aria-hidden="true"></span> @Model.Label
        </NavLink>
    </li>
</OptionalRolesAuthorizeView>
@code {
    [Parameter]
    public MenuItem Model { get; set; }
}

MenuItem.cs

using Microsoft.AspNetCore.Components.Routing;
public class MenuItem
{
    public string Label { get; set; }
    public string Href { get; set; }
    public string IconClass { get; set; }
    public bool RequireAuthentication { get; set; }
    public NavLinkMatch Match { get; set; }
    public string Roles { get; set; }
}

You should also look at policies.

Upvotes: 1

Related Questions