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

InvokeAsync(StateHasChanged) not working on Blazor App

$
0
0

:)I am simply tring to build a web page that displays a few values. Currently they are being sent to an Api but I modified the original application so they are sent to a localhost route. I simply want to display them in a web page so another screen capture program can read them. It's for a golf simulator, don't ask... :D So the values will be updated every 30 seconds maybe and I simply want the new values to appear on the page. Nothing fancy, just numbers and their titles.However, I'm just a materials scientiest turned data engineer so my dev process has mostly been an intense dialogue with ChatGPT as I have simply very little clue about C#, blazor and all the other stuff. I am also not interested in taking 5 days of learning all the details of the framework, I just want a few numbers to be displayed :'( I guess it's a pretty "simple" mistake but I just don't know the issue behind it.

So, here we go. I guess the priject could be better structured, but the issue is the following:I start the application, works fine. localhost shows "Loading..." as designed. However, when I send a curl request, nothing happens. If I reload the page, the values are displayed as designed. However, I want them to be updated without manual refresh. I also couldn't even get the page to refresh manually...

Logs first, then Code... maybe someone can help me, that would be so awesome. I've been frustrated by this for days now...

// Starting the app, opening localhost:8080warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]      Failed to determine the https port for redirect.SignalR connection established.info: System.Net.Http.HttpClient.Default.LogicalHandler[100]      Start processing HTTP request GET http://localhost:8080/wurstbrotinfo: System.Net.Http.HttpClient.Default.ClientHandler[100]      Sending HTTP request GET http://localhost:8080/wurstbrotinfo: System.Net.Http.HttpClient.Default.ClientHandler[101]      Received HTTP response headers after 2046.5032ms - 200info: System.Net.Http.HttpClient.Default.LogicalHandler[101]      End processing HTTP request after 2080.0127ms - 200Raw JSON Response: []// sending curl request curl -X POST http://localhost:8080/wurstbrot -H "Content-Type: application/json" --data-binary @data.json// nothing happens in the browser window, but log says Received update from server: [{"headline":"ClubSpeed","num":120.5}, [more data...]]OnInitializedAsync// even did more logging earlier and it reaches all code points that it should (I'll mark it in Home.razor below)// Now I hit F5 and voila, the numbers appear and...SignalR connection established.info: System.Net.Http.HttpClient.Default.LogicalHandler[100]      Start processing HTTP request GET http://localhost:8080/wurstbrotinfo: System.Net.Http.HttpClient.Default.ClientHandler[100]      Sending HTTP request GET http://localhost:8080/wurstbrotRaw JSON Response: [{"headline":"ClubSpeed","num":120.5},{"headline":"HLA","num":5.2},{"headline":"VLA","num":15.765432},{"headline":"Speed","num":160.8},{"headline":"BackSpin","num":3000.0},{"headline":"SideSpin","num":-150.0},{"headline":"TotalSpin","num":3200.0},{"headline":"SpinAxis","num":45.0},{"headline":"ShotNumber","num":23}]info: System.Net.Http.HttpClient.Default.ClientHandler[101]      Received HTTP response headers after 2013.3491ms - 200info: System.Net.Http.HttpClient.Default.LogicalHandler[101]      End processing HTTP request after 2013.6284ms - 200

Here are the relevant files (I hope...). I wish I could somehow narrow it down to a certain point in the code but I feel like I've tried every possible line that seems to me as it could have any impact on the issue. Oh, and don't judge me, I just left most of the ChatGPT comments in, want to clean all that up as soon as I can get it to work :D

Home.razor (the only page as I don't eben need fancy navigating or so...)

@page "/"@using System;@using System.Text.Json;@using ValueKing.Services;@using Microsoft.AspNetCore.SignalR.Client;@using Microsoft.AspNetCore.SignalR;@inject HttpClient Http@inject AppStateService AppState<PageTitle>Home</PageTitle>@if (AppState.Values == null || !AppState.Values.Any()){<p><em>Loading...</em></p>}else{<div style="display: flex; flex-wrap: wrap; gap: 16px;">        @foreach (var value in AppState.Values)        {<div style="flex: 1 1 calc(33.333% - 16px); border: 1px solid #ccc; padding: 8px; border-radius: 4px;"><h3>@value.Headline</h3><p>@(value.Num?.ToString("F2") ?? "0.00")</p></div>        }</div>}@code {    private HubConnection? hubConnection;    protected override async Task OnInitializedAsync()    {        if (hubConnection == null)        {            // Initialize SignalR connection            hubConnection = new HubConnectionBuilder()                .WithUrl($"http://localhost:8080/datahub")                .Build();        }        // Handle updates from the server        hubConnection.On<string>("UpdateData", async (jsonData) =>        {            Console.WriteLine($"Received update from server: {jsonData}");            // Deserialize updated data and refresh UI            var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };            try            {                var updatedValues = JsonSerializer.Deserialize<List<APIValues>>(jsonData, options);                if (updatedValues != null)                {                    await InvokeAsync(() =>                    {                        // CONSOLE OUTPUT HERE IS WRITTEN AT CURL REQUEST                        Console.WriteLine($"OnInitializedAsync");                        StateChanged(updatedValues);                        // CONSOLE OUTPUT HERE IS ALSO WRITTEN AT CURL REQUEST                    });                }                else                {                    await InvokeAsync(() =>                    {                        StateChanged(new List<APIValues>());                    });                }            }            catch (Exception ex)            {                Console.WriteLine($"Error deserializing update: {ex.Message}");            }        });        try        {            // Start SignalR connection            await hubConnection.StartAsync();            Console.WriteLine("SignalR connection established.");        }        catch (Exception ex)        {            Console.WriteLine($"Error connecting to SignalR hub: {ex.Message}");        }        // Fetch initial data via HTTP GET request        await FetchInitialDataAsync();    }    private async Task FetchInitialDataAsync()    {        try        {            // Fetch the JSON response as a string            HttpResponseMessage response = await Http.GetAsync("http://localhost:8080/wurstbrot");            if (response.IsSuccessStatusCode)            {                string jsonResponse = await response.Content.ReadAsStringAsync();                Console.WriteLine($"Raw JSON Response: {jsonResponse}");                if (!string.IsNullOrWhiteSpace(jsonResponse))                {                    var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };                    try                    {                        // Deserialize the JSON into the values list                        var fetchedValues = JsonSerializer.Deserialize<List<APIValues>>(jsonResponse, options);                        if (fetchedValues != null)                        {                            await InvokeAsync(() =>                            {                                StateChanged(fetchedValues);                            });                        }                    }                    catch (Exception ex)                    {                        Console.WriteLine($"Deserialization error: {ex.Message}");                    }                }                else                {                    Console.WriteLine("Response JSON is empty or null.");                    await InvokeAsync(() =>                    {                        StateChanged(new List<APIValues>());                    });                }            }            else            {                Console.WriteLine($"HTTP request failed with status code {response.StatusCode}");                await InvokeAsync(() =>                {                    StateChanged(new List<APIValues>());                });            }        }        catch (Exception ex)        {            Console.WriteLine($"An error occurred while fetching initial data: {ex.Message}");            await InvokeAsync(() =>            {                StateChanged(new List<APIValues>());            });        }    }    private void StateChanged(List<APIValues> newValues)    {        AppState.Values = newValues;        StateHasChanged();    }    public async ValueTask DisposeAsync()    {        if (hubConnection != null)        {            await hubConnection.DisposeAsync();        }    }}

AppStateService.cs

using ValueKing.Services;public class AppStateService{    private List<APIValues> _values = new List<APIValues>();    public List<APIValues> Values    {        get => _values;        set        {            if (!AreValuesEqual(_values, value)) // Only update if values differ            {                _values = value ?? new List<APIValues>(); // Ensure values are never null            }        }    }    // Helper method to compare lists    private static bool AreValuesEqual(IReadOnlyList<APIValues> list1, IReadOnlyList<APIValues> list2)    {        // bla bla    }}

WurstbrotController.cs

using Microsoft.AspNetCore.Mvc;using Microsoft.AspNetCore.SignalR;namespace ValueKing.Controller{    [ApiController]    [Route("[controller]")]    public class WurstbrotController : ControllerBase    {        private static string _jsonStore = "[]";        private readonly IHubContext<DataHub> _hubContext;        public WurstbrotController(IHubContext<DataHub> hubContext)        {            _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));        }        [HttpGet]        public IActionResult Get()        {            // Ensure the response is JSON content            return Content(_jsonStore, "application/json");        }        [HttpPost]        public async Task<IActionResult> Post([FromBody] object? jsonPayload)        {            if (jsonPayload == null)            {                // bla            }            try            {                // Serialize the JSON payload safely                _jsonStore = System.Text.Json.JsonSerializer.Serialize(jsonPayload);                // Notify all clients of the update                await _hubContext.Clients.All.SendAsync("UpdateData", _jsonStore);                // Return success response                return Ok(new { Message = "JSON successfully updated.", Data = _jsonStore });            }            catch (Exception ex)            {                // bla            }        }    }}

DataService.cs

using System.Text.Json.Serialization;using Microsoft.AspNetCore.Mvc;namespace ValueKing.Services{    public class APIValues    {        [JsonPropertyName("headline")]        public string? Headline { get; set; }        [JsonPropertyName("num")]        public double? Num { get; set; }        // Parameterless constructor required for deserialization        public APIValues() { }        public APIValues(string? headline, double? num)        {            Headline = headline ?? "empty";            Num = num ?? 0.0;        }        // Override Equals for meaningful equality        public override bool Equals(object? obj)        {            if (obj is APIValues other)            {                return string.Equals(Headline, other.Headline, StringComparison.Ordinal)&& Nullable.Equals(Num, other.Num);            }            return false;        }        // Override GetHashCode to ensure consistency with Equals        public override int GetHashCode()        {            return HashCode.Combine(Headline?.GetHashCode(StringComparison.Ordinal), Num);        }    }    [Route("/api")]    [ApiController]    public class DataController : ControllerBase    {        [HttpPost]        public APIValues GetData([FromBody] APIValues values)        {            var data = new APIValues(values.Headline, values.Num);            Console.WriteLine(data);            return data;        }    }}

DataHub.cs

using Microsoft.AspNetCore.SignalR;public class DataHub : Hub{    // Define any server-to-client communication logic if needed}

Viewing all articles
Browse latest Browse all 4839

Trending Articles