Reputation: 117
I am working on a Blazor Server app over a SignalR connection with an ASP.NET Core API, this code works fine in WebAssembly but for some reason it doesn't works in Blazor Server app.
I suspect the problem is that StateHasChanged()
isn't making effect, since Console.WriteLine($"Company Name: {item.CompanyName}, Volumn: {item.Volume}");
is printing in console but MarketData
isn't updating UI at StateHasChanged()
.
For more context; full code is explained here:
https://www.webnethelper.com/2022/01/aspnet-core-6-signalr-creating-real.html
But I guess it's just a common fix; but I can't find the solution.
I've also tried with InvokeAsync(() => StateHasChanged());
as mentioned here in stackoverflow but It didnt work. Can anyone help me fix this issue?
private HubConnection? hubConn;
private string? ConnectionStatusMessage;
public List<Market> MarketData = new List<Market>();
public List<Market> MarketReceivedData = new List<Market>();
private List<string> xSource;
private List<int> ySource;
private List<object> source;
protected override async Task OnInitializedAsync()
{
xSource = new List<string>();
ySource = new List<int>();
source = new List<object>();
await service.GetMarketEndpoint();
await Start();
}
private async Task Start()
{
hubConn = new HubConnectionBuilder().WithUrl("https://localhost:7193/marketdata").Build();
await hubConn.StartAsync();
if(hubConn.State == HubConnectionState.Connected )
ConnectionStatusMessage = "Connection is established Successfully...";
else
ConnectionStatusMessage = "Connection is not established...";
}
private void MarketDataListener(string chartType)
{
hubConn.On<List<Market>>("SendMarketStatusData", async (data) =>
{
MarketData = new List<Market>();
foreach (var item in data)
{
Console.WriteLine($"Company Name: {item.CompanyName}, Volumn: {item.Volume}");
xSource.Add(item.CompanyName);
ySource.Add(item.Volume);
}
source.Add(ySource);
source.Add(xSource);
MarketData = data;
StateHasChanged();
await js.InvokeAsync<object>(chartType, source.ToArray());
xSource.Clear();
ySource.Clear();
});
}
private void ReceivedMarketDataListener()
{
hubConn.On<List<Market>>("CommunicateMarketData", (data) =>
{
MarketReceivedData = data;
StateHasChanged();
});
}
public async Task Dispose()
{
await hubConn.DisposeAsync();
}
async Task generateLineChartTask()
{
MarketDataListener("marketLineChart");
ReceivedMarketDataListener();
await service.GetMarketDataAsync();
}
async Task generateBarChartTask()
{
MarketDataListener("marketBarChart");
ReceivedMarketDataListener();
await service.GetMarketDataAsync();
}
Upvotes: 6
Views: 2453
Reputation: 273169
The main difference here is that Blazor Serverside is multithreaded so the callbacks from the circuit will execute on a different Thread.
StateHasChanged()
has to be executed on the main (UI) thread so call it like InvokeAsync(StateHasChanged)
, which is short for InvokeAsync(() => StateHasChanged())
.
And be aware of other threading risks. Ie, don't share data like Lists between threads.
Upvotes: 3