|
1 | 1 | @page "/" |
2 | 2 | @using Microsoft.AspNetCore.SignalR.Client |
| 3 | +@using FabrikamDashboard.Services |
3 | 4 | @inject NavigationManager Navigation |
4 | 5 | @inject SimulatorClient SimulatorClient |
5 | 6 | @inject ILogger<Home> Logger |
| 7 | +@inject DashboardStateService StateService |
6 | 8 | @implements IAsyncDisposable |
7 | 9 |
|
8 | 10 | <PageTitle>Fabrikam Dashboard</PageTitle> |
|
183 | 185 | { |
184 | 186 | _loadingStartTime = DateTime.UtcNow; |
185 | 187 |
|
186 | | - // Create SignalR connection |
187 | | - _hubConnection = new HubConnectionBuilder() |
188 | | - .WithUrl(Navigation.ToAbsoluteUri("/dashboardHub")) |
189 | | - .WithAutomaticReconnect() |
190 | | - .Build(); |
191 | | - |
192 | | - // Subscribe to dashboard updates |
193 | | - _hubConnection.On<DashboardDataDto>("DashboardUpdate", data => |
194 | | - { |
195 | | - Console.WriteLine($"🔔 SignalR message received - Orders: {data?.TotalOrders}, Tickets: {data?.OpenTickets}, Revenue: {data?.TotalRevenue}"); |
196 | | - |
197 | | - // Check if data is valid (not all zeros) |
198 | | - if (data != null && (data.TotalOrders > 0 || data.OpenTickets > 0 || data.TotalRevenue > 0)) |
199 | | - { |
200 | | - _dashboardData = data; |
201 | | - _lastUpdate = DateTime.UtcNow; |
202 | | - _hasData = true; |
203 | | - _hasError = false; |
204 | | - _isLoading = false; |
205 | | - _consecutiveErrors = 0; |
206 | | - |
207 | | - Console.WriteLine($"✅ Dashboard data updated successfully"); |
208 | | - Logger.LogInformation("✅ Received valid dashboard update: {Orders} orders, {Tickets} tickets, ${Revenue} revenue", |
209 | | - data.TotalOrders, data.OpenTickets, data.TotalRevenue); |
210 | | - } |
211 | | - else if (data != null) |
212 | | - { |
213 | | - // Received empty data - might be initial state or error |
214 | | - _consecutiveErrors++; |
215 | | - Console.WriteLine($"⚠️ Received empty data (attempt {_consecutiveErrors}/{MaxConsecutiveErrors})"); |
216 | | - if (_consecutiveErrors >= MaxConsecutiveErrors && !_hasData) |
217 | | - { |
218 | | - _hasError = true; |
219 | | - _isLoading = false; |
220 | | - Logger.LogWarning("❌ Received {Count} consecutive empty data updates", _consecutiveErrors); |
221 | | - } |
222 | | - else if (!_hasData) |
223 | | - { |
224 | | - Logger.LogInformation("⏳ Received empty data update (attempt {Count}/{Max})", |
225 | | - _consecutiveErrors, MaxConsecutiveErrors); |
226 | | - } |
227 | | - // Keep existing data if we already have some |
228 | | - } |
229 | | - else |
230 | | - { |
231 | | - Console.WriteLine("❌ Received null data from SignalR"); |
232 | | - Logger.LogWarning("Received null dashboard data"); |
233 | | - } |
234 | | - |
235 | | - InvokeAsync(StateHasChanged); |
236 | | - }); |
237 | | - |
238 | | - // Handle reconnection |
239 | | - _hubConnection.Reconnected += async connectionId => |
| 188 | + // Subscribe to state service changes |
| 189 | + StateService.OnDataChanged += HandleDataChanged; |
| 190 | + |
| 191 | + // Get initial data if available |
| 192 | + var initialData = StateService.CurrentData; |
| 193 | + if (initialData != null && (initialData.TotalOrders > 0 || initialData.OpenTickets > 0 || initialData.TotalRevenue > 0)) |
240 | 194 | { |
| 195 | + _dashboardData = initialData; |
| 196 | + _hasData = true; |
| 197 | + _isLoading = false; |
241 | 198 | _isConnected = true; |
242 | | - _isReconnecting = false; |
243 | | - Console.WriteLine($"🔄 Reconnected to dashboard hub - Connection ID: {connectionId}"); |
244 | | - Logger.LogInformation("Reconnected to dashboard hub - Connection ID: {ConnectionId}", connectionId); |
245 | | - await InvokeAsync(StateHasChanged); |
246 | | - }; |
247 | | - |
248 | | - _hubConnection.Reconnecting += async error => |
| 199 | + _lastUpdate = initialData.Timestamp; |
| 200 | + Logger.LogInformation("✅ Loaded initial dashboard data: {Orders} orders, {Tickets} tickets, ${Revenue} revenue", |
| 201 | + initialData.TotalOrders, initialData.OpenTickets, initialData.TotalRevenue); |
| 202 | + } |
| 203 | + else |
249 | 204 | { |
250 | | - _isConnected = false; |
251 | | - _isReconnecting = true; |
252 | | - Console.WriteLine($"⚠️ Reconnecting to dashboard hub... Error: {error?.Message}"); |
253 | | - Logger.LogWarning("Reconnecting to dashboard hub... Error: {Error}", error?.Message); |
254 | | - await InvokeAsync(StateHasChanged); |
255 | | - }; |
| 205 | + Logger.LogInformation("⏳ Waiting for dashboard data from background service..."); |
| 206 | + _isConnected = true; // We're always "connected" to the state service |
| 207 | + } |
256 | 208 |
|
257 | | - _hubConnection.Closed += async error => |
258 | | - { |
259 | | - _isConnected = false; |
260 | | - _isReconnecting = false; |
261 | | - Console.WriteLine($"❌ Dashboard hub connection closed - Error: {error?.Message}"); |
262 | | - Logger.LogError("Dashboard hub connection closed - Error: {Error}", error?.Message); |
263 | | - await InvokeAsync(StateHasChanged); |
264 | | - }; |
| 209 | + await Task.CompletedTask; |
| 210 | + } |
265 | 211 |
|
266 | | - // Start connection |
267 | | - try |
| 212 | + private void HandleDataChanged() |
| 213 | + { |
| 214 | + var data = StateService.CurrentData; |
| 215 | + |
| 216 | + if (data != null && (data.TotalOrders > 0 || data.OpenTickets > 0 || data.TotalRevenue > 0)) |
268 | 217 | { |
269 | | - Console.WriteLine("🔌 Connecting to SignalR dashboard hub..."); |
270 | | - Logger.LogInformation("Attempting to connect to dashboard hub at /dashboardHub"); |
271 | | - |
272 | | - await _hubConnection.StartAsync(); |
273 | | - _isConnected = true; |
274 | | - |
275 | | - Console.WriteLine($"✅ Connected to dashboard hub - State: {_hubConnection.State}"); |
276 | | - Logger.LogInformation("✅ Successfully connected to dashboard hub - Connection State: {State}", _hubConnection.State); |
| 218 | + _dashboardData = data; |
| 219 | + _lastUpdate = data.Timestamp; |
| 220 | + _hasData = true; |
| 221 | + _hasError = false; |
| 222 | + _isLoading = false; |
| 223 | + _consecutiveErrors = 0; |
| 224 | + |
| 225 | + Logger.LogInformation("✅ Received dashboard update: {Orders} orders, {Tickets} tickets, ${Revenue} revenue", |
| 226 | + data.TotalOrders, data.OpenTickets, data.TotalRevenue); |
| 227 | + |
| 228 | + // Trigger UI update on Blazor's synchronization context |
| 229 | + InvokeAsync(StateHasChanged); |
277 | 230 | } |
278 | | - catch (Exception ex) |
| 231 | + else if (data != null) |
279 | 232 | { |
280 | | - Console.WriteLine($"❌ Failed to connect to dashboard hub: {ex.Message}"); |
281 | | - Logger.LogError(ex, "❌ Error connecting to dashboard hub"); |
282 | | - _isConnected = false; |
283 | | - _hasError = true; |
284 | | - _isLoading = false; |
| 233 | + _consecutiveErrors++; |
| 234 | + if (_consecutiveErrors >= MaxConsecutiveErrors && !_hasData) |
| 235 | + { |
| 236 | + _hasError = true; |
| 237 | + _isLoading = false; |
| 238 | + Logger.LogWarning("❌ Received {Count} consecutive empty data updates", _consecutiveErrors); |
| 239 | + InvokeAsync(StateHasChanged); |
| 240 | + } |
285 | 241 | } |
286 | 242 | } |
287 | 243 |
|
|
350 | 306 |
|
351 | 307 | public async ValueTask DisposeAsync() |
352 | 308 | { |
| 309 | + // Unsubscribe from state service |
| 310 | + StateService.OnDataChanged -= HandleDataChanged; |
| 311 | + |
353 | 312 | if (_hubConnection is not null) |
354 | 313 | { |
355 | 314 | await _hubConnection.DisposeAsync(); |
|
0 commit comments