You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SignalR客户端ReceiveClientHub回调未触发及参数为空问题求助

SignalR客户端回调异常及参数为空问题

问题现象

  • 初始状态:FITBSignalRService运行在Fragment中,客户端能正常连接SignalR服务,调用hubConnection.send("BroadcastClient", "adad", "adad")正常,但hubConnection.on("ReceiveClientHub")的回调始终不触发。
  • 更新代码后:回调可以触发,但接收的userId和peerId参数均为null。

初始代码

Java客户端代码

package com.example.fireinthebooth;

import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;

import androidx.annotation.Nullable;

import com.microsoft.signalr.HubConnection;
import com.microsoft.signalr.HubConnectionBuilder;

import java.util.ArrayList;


public class FITBSignalRService  {
    private HubConnection mHubConnection;
    private Handler mHandler; // to display Toast message
    public class PullRequest {
        public String Url;
        public Integer PullRequestId;
        public String Avatar;
        public String Login;
        public String Title;
    }

    ArrayList<PullRequest> pullRequests = new ArrayList<PullRequest>();
    public FITBSignalRService(Activity context, String url) throws InterruptedException {

    HubConnection hubConnection = HubConnectionBuilder
            .create("https://xxxxx/fitbHub")
            .build();


        hubConnection.on("ReceiveClientHub", (ReceivePeerData)-> {
            context.runOnUiThread(new Runnable() {
            @Override
            public void run() {
            }
        });
    }, ReceivePeerData.class);
        hubConnection.start()
                .doOnError(throwable -> {
//start fail , try again
//note: the start function need try chach when we use this function
                })
                .doOnComplete(() -> {
                    //start complated
                    int i = 0;
                    hubConnection.send("BroadcastClient", "adad", "adad");
                })
                .blockingAwait();
}

static class HubConnectionTask extends AsyncTask<HubConnection, Void, Void> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }
    @Override
    protected Void doInBackground(HubConnection... hubConnections) {
        HubConnection hubConnection = hubConnections[0];
        try{
            hubConnection.start();

        }catch(Exception e){
            int g = 0;
        }
        return null;
    }
}

class ReceivePeerData{
        Object userId;
        Object peerId;
}

}

C#服务端代码

using Microsoft.AspNetCore.SignalR;

namespace FireInTheBoothAPI.SignalR
{
    public class FITBHub :Hub
    {
        public async Task BroadcastClient(string userId, string peerId)
        {
            await Clients.All.SendAsync("ReceiveClientHub", userId, peerId);
        }


    }
}

Program.cs代码

using FireInTheBoothAPI.Endpoints;
using FireInTheBoothAPI.SignalR;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSignalR();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();

app.MapControllers();

app.FITB();


app.MapHub<FITBHub>("/fitbHub");

app.Run();

更新后的代码

Java客户端ReceivePeerData类修改为:

class ReceivePeerData{
    public String userId;
    public String peerId;
}

C#服务端修改为:

public class FITBHub :Hub
{
    public async Task BroadcastClient(string userId, string peerId)
    {
        await Clients.All.SendAsync("ReceiveClientHub", new ReceivePeerData() { userId = userId, peerId = peerId });
    }


    class ReceivePeerData
    {
        public string userId;
        public string peerId;
    }
}

问题分析与修复方案

1. 初始回调不触发的原因

服务端调用SendAsync时直接传递了两个独立的字符串参数,但客户端注册回调时期望接收一个ReceivePeerData对象,参数类型不匹配导致SignalR无法找到对应的回调方法,所以回调不触发。

2. 更新后参数为空的原因及修复

虽然两端改成了对象传递,但仍有几个细节需要修正:

  • 服务端嵌套类访问权限:服务端的ReceivePeerData是私有嵌套类,JSON序列化时无法正常识别属性,需改为public,同时建议用属性而非字段提升序列化兼容性:

    public class ReceivePeerData
    {
        public string userId { get; set; }
        public string peerId { get; set; }
    }
    
  • 客户端连接对象生命周期:原代码中hubConnection是构造函数内的局部变量,可能被GC回收导致连接异常,需改为使用类成员变量mHubConnection:

    // 替换构造函数内的局部连接对象
    mHubConnection = HubConnectionBuilder
            .create("https://xxxxx/fitbHub")
            .build();
    
    mHubConnection.on("ReceiveClientHub", (ReceivePeerData data)-> {
        context.runOnUiThread(() -> {
            // 这里可以正常获取data.userId和data.peerId
        });
    }, ReceivePeerData.class);
    
    mHubConnection.start()
            .doOnError(throwable -> {
                // 处理启动错误逻辑
            })
            .doOnComplete(() -> {
                mHubConnection.send("BroadcastClient", "adad", "adad");
            })
            .blockingAwait();
    
  • 序列化一致性:确保两端JSON序列化规则一致,比如属性名称大小写匹配(当前userId小驼峰两端一致,没问题),客户端ReceivePeerData的属性必须是public,且有无参构造函数(Java默认提供,无需额外定义)。

按上述方案修改后,客户端就能正常触发回调并接收正确的参数值。

内容的提问来源于stack exchange,提问作者redoc01

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 10:20:39