问题描述
我无法解决为什么我的 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();