Update:
I was on hurry when asked this question, and left the office, I could add a bit more info to the question, though your answer may solve the earlier posted issue I also want to ask you about this, I have another bigger project that I also work on, BaseUri of HttpClient several times is null in the components and I think as you said and heard can be because of pre-rendering,
builder.Services.AddHttpClient();
So, I want to know your suggestion about the best approach to use HttpClient and best approach to access BaseUri in components and services while we have Pre-rendering.
Here As an example: I checked the more complete project, and I had that line, so I add more info, please check this also.
We have this in Themes.razor:
protected override async Task OnInitializedAsync()
{
// Fetch available themes from server
Themes = await Http.GetFromJsonAsync<List<Theme>>("api/Theme");
}
Also had a controller:
[ApiController]
[Route("api/[controller]")]
public class ThemeController : ControllerBase
{
[HttpGet]
public ActionResult<List<Theme>> GetThemes()
{ ... }
Also I have these in the Program.cs:
builder.Services.AddControllers();
app.MapControllers();
I'm getting this error here:
Exception thrown:
'System.InvalidOperationException' in System.Net.Http.Json.dll An exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll but was not handled in user code An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.
I got this error:
InvalidOperationException: Cannot provide a value for property 'Http' on type 'XBlazor.Components.Themes'. There is no registered service of type 'System.Net.Http.HttpClient'.
Using a simple code with the default template of .NET 9.0:
Themes.razor
:
@* @inject HttpClient Http *@
@* @inject IJSRuntime JSRuntime *@
@namespace XBlazor.Components
<div class="theme-selector">
<div class="selected-theme">
<span class="dropdown-arrow">▼</span>
</div>
</div>
Themes.razor.cs
:
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
namespace XBlazor.Components
{
public partial class Themes
{
[Inject]
protected IJSRuntime JSRuntime { get; set; } = null!;
[Inject]
protected HttpClient Http { get; set; } = null!;
[Inject]
protected NavigationManager Nav { get; set; } = null!;
//public Themes(HttpClient http)
//{
// Http = http;
//}
//protected override void OnInitialized()
//{
// var baseUri = Nav.BaseUri;
//}
public void Something()
{
}
}
}
Program.cs
(Server):
using ExDiv.Client.Pages;
using ExDiv.Components;
var builder = WebApplication.CreateBuilder(args);
// Dunno , added recently
builder.Services.AddServerSideBlazor()
.AddCircuitOptions(options => options.DetailedErrors = true); // Optional: Enable detail
// Add services to the container.
builder.Services.AddRazorComponents()
.AddInteractiveServerComponents()
.AddInteractiveWebAssemblyComponents();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error", createScopeForErrors: true);
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
//app.UseBlazorFrameworkFiles();
app.UseAntiforgery();
app.MapStaticAssets();
app.MapRazorComponents<App>()
.AddInteractiveServerRenderMode()
.AddInteractiveWebAssemblyRenderMode()
.AddAdditionalAssemblies(typeof(ExpandableDiv.Client._Imports).Assembly);
// Map the Blazor Server app
//app.MapBlazorHub(); // Maps SignalR hub for real-time communication
//app.MapFallbackToPage("/_Host"); // Fallback route to load the app
app.Run();
Program.cs
(Client):
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
//builder.RootComponents.Add<App>("#app"); // Adds the app to the <div id="app">
//builder.RootComponents.Add<HeadOutlet>("head::after");
// Register HttpClient with the base address of the server project
builder.Services.AddScoped(sp => new HttpClient
{
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
});
//builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddScoped(sp =>
{
var navManager = sp.GetRequiredService<NavigationManager>();
return new HttpClient { BaseAddress = new Uri(navManager.BaseUri) };
});
await builder.Build().RunAsync();
InvalidOperationException: Cannot provide a value for property 'Http' on type 'XBlazor.Components.Themes'. There is no registered service of type 'System.Net.Http.HttpClient'.
The error indicates you haven't registered Httpclient in DI container instead of null base url
Two solutions for you to solve the issue:
1,Register httpclient in server project to make it available during component prerendering.
builder.Services.AddHttpClient();
2,If prerendering isn't required for the component, disable prerendering by following the guidance in ASP.NET Core Blazor render modes. If you adopt this approach, you don't need to register the service in the main project.
For more details,you could read this document