#c# #asp.net #.net #asp.net-core #blazor
#c# #asp.net #.net #asp.net-core #блейзор
Вопрос:
Я пытался выяснить проблему в течение всего дня и не мог ее понять. Это мой концентратор SignalR (BlazorServerAppHub.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using BlazorServerApp.Data;
namespace BlazorServerApp
{
public class BlazorServerAppHub: Hub
{
public const string HubUrl = "/chat";
public async Task Broadcast(WeatherForecast[] forecasts)
{
await Clients.All.SendAsync("ReceiveMessage", forecasts);
}
public override Task OnConnectedAsync()
{
return base.OnConnectedAsync();
}
}
}
Это страница бизнес-логики (WeatherForecastService.cs)
using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using BlazorServerApp.Data;
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Timers;
namespace BlazorServerApp.Data
{
public class WeatherForecastService
{
private readonly IHubContext<BlazorServerAppHub> _hubContext;
public WeatherForecastService(IHubContext<BlazorServerAppHub> hubContext)
{
_hubContext = hubContext;
}
protected async Task Broadcast()
{
var forecasts = await GetForecastAsync();
await _hubContext.Clients.All.SendAsync("Broadcast", forecasts);
}
public Task<WeatherForecast[]> GetForecastAsync()
{
var rng = new Random();
}
}
public class WeatherForecast
{
public int A { get; set; }
}
}
Наконец, это моя страница razor (fetchData.razor)
@page "/fetchdata"
@using BlazorServerApp.Data;
@inject NavigationManager navigationManager
@using Microsoft.AspNetCore.SignalR.Client;
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>A</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.A</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
private HubConnection _hubConnection;
protected override async Task OnInitializedAsync()
{
string baseUri = navigationManager.BaseUri;
string hubUrl = baseUri.TrimEnd('/') BlazorServerAppHub.HubUrl;
_hubConnection = new HubConnectionBuilder().WithUrl(hubUrl).Build();
_hubConnection.On< WeatherForecast[]>("Broadcast", forcast => { forecasts = forcast; StateHasChanged(); });
await _hubConnection.StartAsync();
}
}
По сути, я пытаюсь получить данные с сервера и периодически передавать их клиенту. Проблема в том, что моя страница, когда я запускаю приложение forecasts
в fetchData.razor, пуста, поэтому на странице отображается «Загрузка». Почему это так? Я предполагаю, что я что-то упускаю в сообщении SignalR.
Комментарии:
1. Настройка концентратора / соединения кажется нормальной. Как вы используете / вызываете
WeatherForecastService
для периодической отправки данных?2. Сначала я хочу показать один пример. Убедитесь, что каждое клиентское соединение может видеть одни и те же данные (поскольку я генерирую их случайным образом). Затем я добавлю эту логику (все еще не уверен на стороне клиента или на стороне сервера). Проблема в том, что он не работает даже для одного образца.
3. Это имеет смысл. Вам все равно нужно вызвать
WeatherForecastService.Broadcast()
сервер, чтобы отправить сообщение клиентам. Вы это где-то делаете?4. По-видимому, это то, чего мне не хватает. Где я мог бы это назвать? Мне нужно, чтобы это запускалось при открытии страницы?
Ответ №1:
Для того чтобы сервер периодически передавал данные клиенту, вам необходимо запустить какую-то фоновую службу. Есть несколько способов сделать это, например:
Однако, поскольку вы сказали, что просто хотите отправить данные один раз в целях тестирования, вы можете подключиться Hub.OnConnectedAsync()
, чтобы отправить данные клиенту при первоначальном подключении. Во-первых, я бы предложил создать отдельный интерфейс / репозиторий для Task<WeatherForecast[]> GetForecastAsync()
:
public interface IWeatherForecastRepository
{
Task<WeatherForecast[]> GetForecastAsync();
}
public class WeatherForecastRepository
{
private static readonly string[] Tickers = new[]
{
"10", "20", "30", "44", "77"
};
private static readonly int[] Ones = new[]
{
1000, 15000, 7000, 500, 2200
};
public Task<WeatherForecast[]> GetForecastAsync()
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
A = index,
B = Tickers[index - 1],
C = NextFloat(rng),
D = Ones[index - 1],
E = rng.Next(0, 10000),
}).ToArray());
}
static float NextFloat(Random random)
{
double decimalPart = random.NextDouble();
double intPart = random.Next(0, 1000);
return (float)Math.Round(intPart decimalPart, 3); ;
}
}
Затем, как только вы зарегистрируете этот репозиторий с помощью DI, вы можете внедрить его в свой BlazorServerAppHub
и использовать в OnConnectedAsync()
:
public class BlazorServerAppHub : Hub
{
public const string HubUrl = "/chat";
private readonly IWeatherForecastRepository _weatherForecastRepository;
public BlazorServerAppHub(IWeatherForecastRepository weatherForecastRepository)
{
_weatherForecastRepository = weatherForecastRepository;
}
public async Task Broadcast(WeatherForecast[] forecasts)
{
await Clients.All.SendAsync("ReceiveMessage", forecasts);
}
public override async Task OnConnectedAsync()
{
await base.OnConnectedAsync();
var forecasts = await _weatherForecastRepository.GetForecastAsync();
// Clients.Caller will only send the data to the client that just connected
await Clients.Caller.SendAsync("Broadcast", forecasts);
}
}
Комментарии:
1. @Gray_Rhino без проблем. Код кажется достаточно общим, чтобы все было в порядке, но, конечно, не стесняйтесь удалять его, если нет