:)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 - 200Here 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}