I have an app created from a new .Net 8 Blazor template for Visual Studio. Interactive render mode: WebAssembly Interactive location: Global The template creates two projects: Server, Client
The problem is - when I try to load data from API using HttpClient within the OnInitialized method, I get an error that HttpClient is not a registered service. That is happening because the app tries to pre-render the page on the server, and on the server, there is no registered HttpClient service.
I spent two days trying to resolve the issue, and found two kinds of solutions, that still do not work for me:
Create a shared interface and create two service classes (ClientService, ServerService) inherited from it on both the Server and Client projects. And then within OnInitialized method call the ClientService. During prerendering on the server via dependency injection, ServerService will be called instead. This method is not suitable for my scenario as it does not hit controller's authorization mechanism, and goes straight to data fetch from the service. https://blazor.syncfusion.com/documentation/common/how-to/create-blazor-webassembly-prerendering
Register named HttpClient both on the server and client. In the new Blazor Web App template using .net 8, how do I make an HTTP request from a InteractiveWebAssembly mode component?
services.AddHttpClient("MyClient", client =>
{
client.BaseAddress = new Uri("https://localhost:7110/");
});
But I couldn't make this work. simply using @inject HttpClient HttpClient on the page seems does not work, and throws an error.
In reality, I don't need the data fetched on the server. I need it only when the component got initialized on the client, like in pre-.Net 8 (6, 7) Blazor Webassembly. One piece of advice was to fetch data within the OnAfterRender method. But OnAfterRender runs a bit late compared to OnInitialized. For example in .Net 7 OnInitialized runs before the rendering takes place. But unlike .Net 8 it does not run both on the Server and Client, only on Client.
In other words I want to prerender all UI elements, except for API calls. Any thoughts on how to properly set it up?
Below are my project files.
Program.cs on Client:
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
Home.razor on Client:
@page "/"
@inject HttpClient HttpClient
<div>Elements: @forecasts?.Count()</div>
Some UI controls here
@code {
IEnumerable<Weather>? forecasts;
protected override async Task OnInitializedAsync()
{
// run this part of code only when component (page) initialized on client-side
forecasts = await HttpClient.GetFromJsonAsync<IEnumerable<Weather>>("api/weather/list");
}
}
WeatherController.cs on Server
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class WeatherController : ControllerBase
{
ILogger<WeatherController> _logger;
public WeatherController(ILogger<WeatherController> logger)
{
_logger = logger;
}
[HttpGet]
[Route("list")]
public async Task<ActionResult<IEnumerable<Weather>>> GetList()
{
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
var result = Enumerable.Range(1, 5).Select(index => new Weather
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
});
return Ok(result);
}
}
OnAfterRender{async}. It's bad advice.OnAfterRender{async}is not a lifecycle method, it's a UI Event triggered by a DOM render.