为什么我的 Azure SignalR Hub 方法没有被触发?

问题描述

我无法解决为什么我的 Azure SignalR Hub 方法没有被触发?

环境:Xamarin.Forms 客户端

免责声明:

我的 LocationHub 类位于一个单独的项目中,该项目由托管我的 Azure 函数的项目引用。

Azure SignalR 能否调用位于单独库中的集线器方法

服务器:这是集线器类:

type LocationHub()  =

    inherit Hub()

    member x.SendLocation(v:SubjectLocation) =

        async { do! (x :> Hub).Clients.All.SendAsync($"{v.SessionId}",v) |> Async.AwaitTask } |> Async.StartAsTask

服务器:这里是假设触发 hub 类上的方法的 Azure 函数

public static class LocationFn
    {
        [FunctionName(nameof(LocationFn))]
        public static async Task<IActionResult> Run(
            [HttpTrigger(
                AuthorizationLevel.Anonymous,"post",Route = "locationfn")]
            HttpRequest req,[SignalR(HubName = "LocationHub")]
            IAsyncCollector<SignalRMessage> signalRMessages,ILogger log)
        {
            log.Loginformation($"{nameof(LocationFn)} has been invoked.");

            try
            {
                using (var streamReader = new StreamReader(req.Body))
                {
                    var json = await streamReader.ReadToEndAsync();
                    var subjectLocation = JsonConvert.DeserializeObject<SubjectLocation>(json);

                    await signalRMessages.AddAsync(
                        new SignalRMessage
                        {
                            Target    = "SendLocation",Arguments = new[] { subjectLocation }
                        });

                    var message = Log(log,subjectLocation);

                    return new OkObjectResult(message);
                }
            }
            catch (Exception ex)
            {
                return new BadRequestObjectResult("There was an error: " + ex.Message);
            }
        }

        static string Log(ILogger log,SubjectLocation subjectLocation)
        {
            var location  = subjectLocation.Location;
            var latitude  = location.Latitude;
            var longitude = location.Longitude;

            var message = $"Received location: {subjectLocation.SubjectId} at '({latitude},{longitude})'";
            log.Loginformation($"{nameof(LocationFn)} {message}");
            return message;
        }
    }

附录:

客户我有以下客户请求:

var sessionId = "some_session_id";
await CourierTracking.connectOn(sessionId,locationTracking(),"negotiatefn");

Client:建立连接的鸟瞰图在这里实现:

open System.Diagnostics
open OrderRequest.SignalR.Client

module CourierTracking =

    let private onConnectionChanged (_,_) = ()
    let private onMessageReceived msg = Debug.WriteLine(sprintf "%A" msg)

    let private signalR = Signalrservice();

    let connectOn(sessionId:string) (serviceHost:string) (resourceName:string) =

        signalR.Connected        .Add onConnectionChanged
        signalR.ConnectionFailed .Add onConnectionChanged
        signalR.MessageReceived  .Add onMessageReceived

        async {
        
            do! signalR.ConnectOn(serviceHost,resourceName,sessionId) |> Async.AwaitTask
        
        } |> Async.StartAsTask

客户端:这是连接和接收消息的核心实现:

public class Signalrservice
{
    HttpClient _client = new HttpClient();

    public delegate void MessageReceivedHandler(object sender,CourierLocation message);
    public delegate void ConnectionHandler(object sender,bool successful,string message);

    public event MessageReceivedHandler MessageReceived;
    public event ConnectionHandler      Connected;
    public event ConnectionHandler      ConnectionFailed;

    public bool IsConnected { get; private set; }
    public bool IsBusy      { get; private set; }

    public async Task ConnectOn(string host,string nameOfNegotiationFn,string sessionId)
    {
        try
        {
            IsBusy = true;

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            var negotiateJson = await _client.GetStringAsync($"{host}{nameOfNegotiationFn}");
            var negotiate     = JsonConvert.DeserializeObject<NegotiateInfo>(negotiateJson);

            var connection = new HubConnectionBuilder()
                .AddNewtonsoftJsonProtocol()
                .WithUrl(negotiate.Url,options => options.AccesstokenProvider = async () => negotiate.Accesstoken)
                .Build();

            connection.Closed += Connection_Closed;
            connection.On<JObject>(sessionId,OnIncomingMessage);
            await connection.StartAsync();

            IsConnected = true;
            IsBusy = false;

            Connected?.Invoke(this,true,"Connection successful.");
        }

        catch (Exception ex)
        {
            ConnectionFailed?.Invoke(this,false,ex.Message);
            IsConnected = false;
            IsBusy = false;
        }
    }

    Task Connection_Closed(Exception arg)
    {
        ConnectionFailed?.Invoke(this,arg.Message);
        IsConnected = false;
        IsBusy = false;
        return Task.CompletedTask;
    }

    void OnIncomingMessage(JObject message)
    {
        var courierId = message.GetValue("SubjectId").ToString();
        var location  = message.SelectToken("Location");
        var latitude  = double.Parse(location.SelectToken("Latitude").ToString());
        var longitude = double.Parse(location.SelectToken("Longitude").ToString());

        var courierLocation = new CourierLocation(courierId,new Coordinate(latitude,longitude));
        MessageReceived?.Invoke(this,courierLocation);
    }
}

解决方法

我需要客户端传入它订阅的集线器方法的确切名称:

var hubMethodName = "LocationUpdate";

...

var connection = new HubConnectionBuilder()
    .AddNewtonsoftJsonProtocol()
    .WithUrl(negotiate.Url,options => options.AccessTokenProvider = async () => negotiate.AccessToken)
    .Build();

connection.Closed -= Connection_Closed;
connection.Closed += Connection_Closed;
connection.On<JObject>(hubMethodName,OnIncomingMessage); //  ** REF: HUB METHOD NAME **
await connection.StartAsync();