I have a Blazor component that needs to get data via the API, the problem is I call fetch API in OnInitializedAsync function, so every time I render the component the fetch API will call.
Because the results of data are the same in these components, so I want to call API once time and cache in session storage to reuse
My idea is to implement SemaphoreSlim service and the others call to it should be waiting until it is released, and I can reuse the data from storage. I don't know if this is a bad or good idea. Could you please share your opinion and some other ideas to do this? Thank you for your response.
This is my code
// Razor code bindpublic class DateEdit: ComponentBase{ [Inject] ICalendDataListService calendDataListService { get; set; } List<Calend> listData; protected override async Task OnInitializedAsync() { listData = await calendDataListService.GetDataByDays( new DateOnly(DateTime.Now.Year, 1, 1).ToString("yyyyMMdd"), new DateOnly(DateTime.Now.Year, 12, 31).ToString("yyyyMMdd")); }}// Servicepublic interface ICalendDataListService{ Task<List<Calend>> GetDataByDays(string startdate, string enddate, CancellationToken token = default);}public class CalendDataListService : ICalendDataListService{ private IJSInProcessRuntime _jSInProcessRuntime; private static readonly SemaphoreSlim _semaphore = new(initialCount: 1, 1); private NavigationManager navigationManager; public CalendDataListService(IJSInProcessRuntime jSInProcessRuntime, NavigationManager navigationManager) { _jSInProcessRuntime = jSInProcessRuntime; this.navigationManager = navigationManager; } public async Task<List<Calend>> GetDataByDays(string startdate, string enddate, CancellationToken token = default) { try { await _semaphore.WaitAsync(token); Console.WriteLine($"Starting get api at {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff", CultureInfo.InvariantCulture)}"); var calendars = await GetData(startdate, enddate, token); if (calendars is null) return []; return calendars.Where(e => string.Compare(startdate[..6], e.CalenYm) <= 0 && string.Compare(enddate[..6], e.CalenYm) >= 0).ToList(); } catch (Exception ex) { Console.WriteLine($"{ex.Message}"); return []; } finally { _semaphore.Release(); } } private async Task<List<Calend>?> GetData(string startdate, string enddate, CancellationToken token = default) { HttpClient _httpClient = new HttpClient() { BaseAddress = new Uri(navigationManager.BaseUri) }; string key = $"calendar_{startdate[..4]}"; string dataFromStorage = _jSInProcessRuntime.Invoke<string>("sessionStorage.getItem", key); if (dataFromStorage is not null) { return System.Text.Json.JsonSerializer.Deserialize<List<Calend>>(dataFromStorage)!; } var calendars = await _httpClient.GetFromJsonAsync<List<Calend>>("./calendar.json", token); _jSInProcessRuntime.Invoke<string>("sessionStorage.setItem", key, System.Text.Json.JsonSerializer.Serialize(calendars)); return calendars; }}