Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SignalR Dynamic HubName

I'm using an Azure Function to read messages off an Event Hub and post them to a SignalR instance. I have frontend JavaScript that is connected to the SignalR instance and is receiving messages. What I want is to dynamically set the "HubName" attribute in my Azure Function base off a value passed in. Is this poissble? I have included my Azure Function calls below. In both methods, I would like to dynamically set the HubName value, which is hard coded to 'deviceMessages'

    public static SignalRConnectionInfo GetSignalRInfo(
        [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
        [SignalRConnectionInfo(HubName = "deviceMessages")] SignalRConnectionInfo connectionInfo)
    {
        return connectionInfo;
    }


    public static Task SendMessage(
        [EventHubTrigger("{EventHubName}", Connection = "EventHubConnectionAppSetting")]string myEventHubMessage,
        [SignalR(HubName = "deviceMessages")] IAsyncCollector<SignalRMessage> signalRMessages)
    {
        return signalRMessages.AddAsync(
            new SignalRMessage
            {
                Target = "newMessage",
                Arguments = new[] { myEventHubMessage }
            });
    }
like image 512
jvencl Avatar asked Dec 17 '22 20:12

jvencl


2 Answers

You can do binding the imperative way. Use IBinder binder in the signature of your function and you can create bindings at runtime.

var signalRAttribute = new SignalRAttribute(/* your settings here */));
var outputMessages = await binder.BindAsync<IAsyncCollector<SignalRMessage>>(signalRAttribute);

There are also good samples for this here:

How do I use Binder to perform dynamic bindings in my C# Function?

and here:

https://weblogs.asp.net/sfeldman/azure-functions-to-make-audit-queue-and-auditors-happy

like image 113
Sebastian Achatz Avatar answered Dec 30 '22 18:12

Sebastian Achatz


I found a separate way around this issue, by using the UserId property of the SignalRConnectionInfo object. I pass the id of the device I want to receive messages for in the 'negotiate' call using a custom header field, which returns a token for that id. I then set that value in the SignalRMessage object when a message is received from the Event Hub. This way, the device page that I'm on is only receiving message that that particular device is sending.

    [FunctionName("negotiate")]
    public static SignalRConnectionInfo GetSignalRInfo(
        [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req,
        [SignalRConnectionInfo(HubName = "deviceMessages", UserId = "{headers.deviceId}")] SignalRConnectionInfo connectionInfo)
    {
        return connectionInfo;
    }

    [FunctionName("messages")]
    public static Task SendMessage(
        [EventHubTrigger("{EventHubName}", Connection = "EventHubConnectionAppSetting")]string myEventHubMessage,
        [SignalR(HubName = "deviceMessages")] IAsyncCollector<SignalRMessage> signalRMessages)
    {
        var dev = JToken.Parse(Convert.ToString(myEventHubMessage));
        DeviceMessage msg = dev.ToObject<DeviceMessage>();

        return signalRMessages.AddAsync(
            new SignalRMessage
            {
                UserId = msg.deviceId,
                Target = "newMessage",
                Arguments = new[] { myEventHubMessage }
            });
    }
like image 31
jvencl Avatar answered Dec 30 '22 17:12

jvencl