I'm using the basic template that VS 2019 provides with the weather forecasting data when creating a ASP.NET WebAPI project and added some very basic authentication with user login and support for JWT Token which all works fine.
I'm trying to create a blazor client project to consume the API and display the data on the page. AFAIK Blazor doesn't support localstorage so I'm using Blazored LocalStorage package to give me this ability. My problem stems from fact using JS via OnInitializedAsync() is not possible in server-side blazor (https://github.com/aspnet/AspNetCore/issues/13396) as a result I'm not sure how one is suppose to consume these web api calls. As this will produce a null reference exception
protected override async Task OnInitializedAsync()
{
var client = HttpFactory.CreateClient();
var token = await LocalStorage.GetItemAsync<string>("authToken");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync("url/WeatherForecast");
var str = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
}
One suggestion was to use OnAfterRenderAsync() method to call them as JS would be ready by then. Which semi-works but obviously the UI doesn't match because it needs to be refreshed - however to manually refresh it seems I have to call StateHasChanged(); which in turn calls OnAfterRender method again and as a result I had to put a check but this ultimately feels incredibly hacky.
private bool hasRendered;
protected override async Task OnAfterRenderAsync(bool _)
{
if (!hasRendered) return;
var client = HttpFactory.CreateClient();
var token = await LocalStorage.GetItemAsync<string>("authToken");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await client.GetAsync("https://url/WeatherForecast");
var str = await response.Content.ReadAsStringAsync();
Items = JsonConvert.DeserializeObject<IEnumerable<WeatherForecast>>(str);
StateHasChanged();
hasRendered = true;
}
What is the correct way to consume an API with authnetication and display the data correctly on the client side?
Side question HttpClient doesn't seem to be injectable in server-side and it's recommended to use HttpClientFactory - is it a good idea to create a client on every request or make a singleton and re-use thoughout the client project?