Quantcast
Channel: Active questions tagged blazor - Stack Overflow
Viewing all articles
Browse latest Browse all 4839

In .Net 8 Blazor app how to fetch data only on client, while keeping prerender on the server

$
0
0

I have an app created from a new .Net 8 Blazor template for Visual Studio.Interactive render mode: WebAssemblyInteractive location: GlobalThe 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:

  1. 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

  2. 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);        }    }

Viewing all articles
Browse latest Browse all 4839

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>