Understanding Blazor’s Pre-rendering Behavior: Why Your Service Injection Might Fail

Understanding Blazor’s Pre-rendering Behavior: Why Your Service Injection Might Fail

4/3/2025 by InstanceMaster (Updated 4/17/2025)

If you’ve been working with Blazor lately, especially using the latest project templates in .NET 8, you might have run into a frustrating and seemingly inexplicable error when injecting services into your components:

InvalidOperationException: Cannot provide a value for property 'Service' on type MyPage. There is no registered service of type MyService.

You double-check your Program.cs, and your service is clearly registered:

builder.Services.AddScoped<MyService>();

So what’s going on?

Let’s break it down.

The Setup: A Typical Blazor Project

You create a new Blazor project using the default "Blazor App" template in Visual Studio. This template sets up a hybrid server/WASM application using the new interactive rendering features introduced in .NET 8. You then:

  • Add a page/component
  • Register a service in the client-side Program.cs
  • Inject the service in the component:
@inject MyService Service

And… boom. You get an error about the service not being registered.

The Cause: Pre-rendering in Disguise

Even though you might be using:

@rendermode="InteractiveWebAssembly"

Blazor still performs a server-side render pass first, unless you explicitly disable it. During that pass, your component is being rendered on the server — and the service you're injecting only exists in the client.

This is the key misunderstanding: InteractiveWebAssembly does not mean "pure client-side." It still pre-renders on the server unless you turn that off. To fix this, you need to use:

@rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)"

This disables the server-side pre-render and ensures everything happens on the client, as many expect.

The Project Template Trap

Here’s the kicker: if you really want to build a classic Blazor WebAssembly app with no server-side rendering or SignalR circuit setup, you should choose the "Blazor WebAssembly App" template, not the generic "Blazor App".

The "Blazor App" template wires up everything to support SSR, SignalR, and interactivity across client/server boundaries by default. That’s why the pre-rendering behavior comes along for the ride.

Workarounds and Best Practices

Option 1: Disable Pre-rendering

If you're building a pure WASM experience, turn off prerendering explicitly:

@rendermode="new InteractiveWebAssemblyRenderMode(prerender: false)"

Option 2: Register Services on Both Server and Client

Create an extension method like AddClientServices() and call it in both server and client Program.cs files. This ensures your shared services are available regardless of the rendering phase.

⚠️ Note: When using this approach, be aware that your component will be rendered twice — once during server-side prerendering and again on the client during hydration. This can lead to performance overhead and subtle issues if your component interacts with non-idempotent services or DOM elements.

To mitigate this, consider using persisted prerendered state to avoid re-running logic unnecessarily during hydration. See the next article about dealing with persisted prerendered state: Handle Pre-rendering Right in Blazor

Final Thoughts

Pre-rendering in Blazor can provide a better user experience and improve perceived performance — if you understand how it works and how your services are wired up.

But for many developers, especially those coming from a client-first mindset, it introduces a non-obvious source of runtime errors.

So:

  • Be intentional about the project template you choose.
  • Be explicit about prerendering if you don’t need it.
  • Consider using shared service registration patterns to make your code more robust.

Thanks to the awesome Blazor community for sharing insights, workarounds, and thoughtful discussion on this topic. It’s nice to know I’m not the only one who got caught by this!


Have you hit this issue yourself? Got a different approach? I’d love to hear your experience in the comments.