【问题标题】:SignalR client-server connection issueSignalR 客户端-服务器连接问题
【发布时间】:2021-03-09 10:06:20
【问题描述】:

我一整天都在试图找出问题所在,但无法弄清楚。 这是我的 SignalR Hub (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; }

    }
}

最后,这是我的剃须刀页面(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();
    }
}

基本上,我正在尝试从服务器获取数据并定期将其推送到客户端。当我在 FetchData.razor 中运行应用程序 forecasts 时,问题是我的页面为空,因此页面显示“正在加载”。这是为什么?我的猜测是我在 SignalR 通信中遗漏了一些东西。

【问题讨论】:

  • 集线器/连接设置似乎没问题。您如何使用/调用WeatherForecastService 定期推送数据?
  • 首先,我想展示一个示例。确保每个客户端连接都可以看到相同的数据(因为我随机生成它们)。然后我将添加该逻辑(在客户端或服务器端仍然不确定)。问题是它甚至不适用于一个样本。
  • 这是有道理的。您仍然需要在服务器上调用WeatherForecastService.Broadcast() 才能将消息发送给客户端。你是在哪里做的吗?
  • 显然,这就是我所缺少的。我怎么可能这么称呼它?我需要在页面打开时运行它吗?

标签: c# asp.net .net asp.net-core blazor


【解决方案1】:

为了让服务器定期将数据推送到客户端,您需要运行某种后台服务。有很多方法可以做到这一点,例如:

但是,由于您说您只想发送一次数据用于测试目的,您可以连接到Hub.OnConnectedAsync(),以便在客户端最初连接时将数据发送给客户端。首先,我建议为Task&lt;WeatherForecast[]&gt; 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);
    }
}

【讨论】:

  • @Gray_Rhino 没问题。代码看起来足够通用,没问题,但如果不是,当然可以随意删除它
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-21
  • 2012-07-04
  • 2012-08-31
  • 1970-01-01
相关资源
最近更新 更多