I just added Identity to my existing Blazor Server project using Identity Scaffolding. I followed this Microsoft learn guide here.
However, since Identity uses Razor pages instead of Razor components, the styling of the UI changes when a visitor navigates between Identity pages and components.
For eg: The page initially loads like this:
And when the user hits the Login
link at the top right corner, the login page opens which looks so ugly 😩:
To fix that, I tried to follow this guide at Microsoft learn. But I'm hit with this error (code link here) 😩:
The name 'Engine' does not exist in the current context
Can someone please guide me in the right direction for styling Identity Razor Pages in Blazor to get a consistent look and feel with rest of the app? Microsoft learn guide seems to be lacking.
The documentation totally misses these 2 lines that need to be added to the top of _Layout.cshtml
file:
@using Microsoft.AspNetCore.Mvc.ViewEngines
@inject ICompositeViewEngine Engine
Adding those lines resolved the error.
However, I didn't even go that route at the end.
If you're interested in my complete solution, this is what I ended up doing:
In summary, I took MainLayout.razor and put it inside _Layout.cshtml.
If the steps mentioned below are hard to follow, take a look at the code. The full source code is here.
Unauthorized View
Login Page
Authorized View
Since we're using NavMenu and LoginDisplay razor components inside _Layout.cshtml, add these to the top of _Layout.cshtml:
@using HMT.Web.Server.Features.Shared.Layout.NavMenu
@using HMT.Web.Server.Features.Identity
Replace <body>
with this:
<body>
<div class="page">
<div class="sidebar">
<component type="typeof(NavMenu)" render-mode="ServerPrerendered" />
</div>
<main>
<div class="top-row px-4 logindisplay">
<component type="typeof(LoginDisplay)" render-mode="ServerPrerendered" />
</div>
<article class="content px-4">
@RenderBody()
</article>
<div class="bottom-row px-4">
<a href="">
<img src="/images/logo-black.png" width="40"/>
<span class="fs-4">HMT</span>
</a>
</div>
<div id="blazor-error-ui">
<environment include="Staging,Production">
An error has occurred. This application may no longer respond until reloaded.
</environment>
<environment include="Development">
An unhandled exception has occurred. See browser dev tools for details.
</environment>
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
</main>
</div>
<script src="~/Identity/lib/jquery/dist/jquery.js"></script>
<script src="~/Identity/lib/bootstrap/dist/js/bootstrap.bundle.js"></script>
<script src="~/Identity/js/site.js" asp-append-version="true"></script>
@RenderSection("Scripts", required: false)
<script src="_framework/blazor.server.js"></script>
</body>
If you're thinking that I just cut and pasted <div class="page">
section from MainLayout.razor, you're absolutely right.😁
Create: Features/Shared/Layout/_Layout.cshtml.css file. Now cut and paste all the css styles from your MainLayout.razor.css to _Layout.cshtml.css. For reference, this is how mine looks like.
All that remains inside MainLayout.razor is this:
@inherits LayoutComponentBase
<PageTitle>Handy Man's Tool</PageTitle>
@Body
Wrap AuthorizeView
in LoginDisplay.razor with <CascadingAuthenticationState>
.
The reason is that if you try to use a Razor Component that has Authorize
components from component that IS NOT
wrapped with <CascadingAuthenticationState>
, it won't work,
That is the reason why <component type="typeof(LoginDisplay)" render-mode="ServerPrerendered" />
doesn't work in _Layout.cshtml without it.
If you want to protect the NavLinks in NavMenu, wrap them inside AuthorizeView
, and since NavMenu is rendered
from _Layout.cshtml, don't forget to wrap them inside <CascadingAuthenticationState>
.
For eg: Mine looks like this:
<CascadingAuthenticationState>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<AuthorizeView>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data
</NavLink>
</div>
</AuthorizeView>
</nav>
</div>
</CascadingAuthenticationState>
Remove the following files as they're unnecessary:
https://github.com/akhanalcs/blazor-server-auth/tree/feature/LayoutWithIdentityPages