DEV Community

assaadfrs
assaadfrs

Posted on

Fixing Blazor 404 Errors When Using Razor Class Library Pages

Have you ever created a Blazor page in a Razor Class Library (RCL) only to get a frustrating 404 error when trying to navigate to it? You're not alone! This is a common issue that catches many developers off guard. Let me walk you through the problem and the solution.

TL;DR

Problem: Blazor pages in Razor Class Libraries return 404 errors even when AdditionalAssemblies is configured in Routes.razor.

Solution: Add .AddAdditionalAssemblies() to your Program.cs routing configuration:

app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(YourRCL.SomeComponent).Assembly); 
Enter fullscreen mode Exit fullscreen mode

You need to configure additional assemblies in both Routes.razor AND Program.cs for RCL routing to work properly.

The Problem

I had a Blazor Server app (BlazorApp1) that referenced a Razor Class Library (RazorClassLibrary1). In the RCL, I created a simple page:

@page "/page1" <PageTitle>Page 1</PageTitle> <h1>Page 1</h1> <div class="my-component"> This component is defined in the <strong>RazorClassLibrary1</strong> library. </div> 
Enter fullscreen mode Exit fullscreen mode

I configured the AdditionalAssemblies in my Routes.razor file:

@using System.Reflection <Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(RazorClassLibrary1.Component1).Assembly }"> <Found Context="routeData"> <RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"/> <FocusOnNavigate RouteData="routeData" Selector="h1"/> </Found> <NotFound> <PageTitle>Not found</PageTitle> <LayoutView Layout="typeof(Layout.MainLayout)"> <p role="alert">Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router> 
Enter fullscreen mode Exit fullscreen mode

Everything looked correct, but navigating to /page1 still returned a 404 error. Frustrating!

The Investigation

To debug this issue, I created a diagnostic page that showed me what routes were being discovered:

@page "/debug" @using System.Reflection @using Microsoft.AspNetCore.Components.Routing <h3>Debug Routes</h3> <h4>Main Assembly Routes:</h4> <ul> @foreach (var route in GetRoutes(typeof(Program).Assembly)) { <li>@route</li> } </ul> <h4>RCL Assembly Routes:</h4> <ul> @foreach (var route in GetRoutes(typeof(RazorClassLibrary1.Component1).Assembly)) { <li>@route</li> } </ul> @code { private List<string> GetRoutes(Assembly assembly) { var routes = new List<string>(); foreach (var type in assembly.GetTypes()) { var routeAttributes = type.GetCustomAttributes<RouteAttribute>(); foreach (var attr in routeAttributes) { routes.Add($"{type.Name}: {attr.Template}"); } } return routes; } } 
Enter fullscreen mode Exit fullscreen mode

The debug page showed that the /page1 route was being discovered from the RCL assembly, but the router still wasn't finding it at runtime.

The Solution

The issue was that while the Router component was configured with AdditionalAssemblies, the routing system in Program.cs wasn't aware of the RCL assembly.

The fix is to also register the additional assemblies in Program.cs:

using BlazorApp1.Components; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); var app = builder.Build(); // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); app.UseHsts(); } app.UseHttpsRedirection(); app.UseAntiforgery(); app.MapStaticAssets(); app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(RazorClassLibrary1.Component1).Assembly); // 👈 This is the key! app.Run(); 
Enter fullscreen mode Exit fullscreen mode

Why This Works

The problem occurs because:

  1. The Router component in Routes.razor handles client-side routing within the Blazor app
  2. The MapRazorComponents in Program.cs handles server-side route discovery and registration
  3. Both need to know about the RCL assemblies for the routing to work properly

By adding .AddAdditionalAssemblies() to the MapRazorComponents call, we ensure that:

  • The server-side routing system discovers all routes from the RCL
  • The routes are properly registered with the ASP.NET Core routing system
  • The Blazor router can successfully match and render the pages

Complete Working Configuration

Here's the complete working setup:

Program.cs:

app.MapRazorComponents<App>() .AddInteractiveServerRenderMode() .AddAdditionalAssemblies(typeof(RazorClassLibrary1.Component1).Assembly); 
Enter fullscreen mode Exit fullscreen mode

Routes.razor:

@using System.Reflection <Router AppAssembly="typeof(Program).Assembly" AdditionalAssemblies="new[] { typeof(RazorClassLibrary1.Component1).Assembly }"> <Found Context="routeData"> <RouteView RouteData="routeData" DefaultLayout="typeof(Layout.MainLayout)"/> <FocusOnNavigate RouteData="routeData" Selector="h1"/> </Found> <NotFound> <PageTitle>Not found</PageTitle> <LayoutView Layout="typeof(Layout.MainLayout)"> <p role="alert">Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router> 
Enter fullscreen mode Exit fullscreen mode

Project Reference in BlazorApp1.csproj:

<ItemGroup> <ProjectReference Include="..\RazorClassLibrary1\RazorClassLibrary1.csproj" /> </ItemGroup> 
Enter fullscreen mode Exit fullscreen mode

Key Takeaways

  1. Both client and server routing need to know about RCL assemblies - Configure both Routes.razor and Program.cs
  2. The diagnostic page technique is invaluable - Create a debug page to verify route discovery
  3. This applies to any additional assemblies - Not just RCLs, but any external assemblies containing Blazor components

This solution has saved me hours of debugging, and I hope it helps you too! Have you encountered this issue before? What other Blazor routing gotchas have you discovered?


Found this helpful? Give it a ❤️ and share it with your fellow Blazor developers!

Top comments (0)