How do you hit a SignalR ServerlessHub method?

339 Views Asked by At

I'm trying to move my app using SignalR from a "traditional server based" to an Serverless Azure Function App. I have no problem hitting the Negotiate method, but my most basic client-to-server method will not fire.

// Server endpoints...
namespace TooDuh.Serverless.Hubs
{
  public class TestHub: ServerlessHub
  {
        [FunctionName("negotiate")]
        public SignalRConnectionInfo Negotiate( [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req )
        {
            var claims = GetClaims(req.Headers["Authorization"]);
            var connectionInfo = Negotiate( req.Headers["x-ms-signalr-user-id"], claims );

            return connectionInfo;
        }

        [FunctionName("SendMessage")]
        public async Task SendMessage(
            [SignalRTrigger] InvocationContext invocationContext, string message, ILogger logger)
        {
            logger.LogInformation($"Receive {message} from {invocationContext.ConnectionId}.");

            char[] stringArray = message.ToCharArray();
            Array.Reverse(stringArray);
            string reversedStr = new string(stringArray);

            await Clients.All.SendAsync("ReceiveMessage", reversedStr);

        }
...
// Client method...
async function sendToServer(){
  try {
    console.log("[Client.SignalR.SendMessage] " + userInput.value);
    await connection.invoke("SendMessage", userInput.value);
  } catch (err) {
    console.error(err);
  }
}

Is there something different I'm supposed to do with the bindings? The docs are a real scramble, but I'm trying to work from AzureSignalR-samples/BidirectionChat on GitHub... which does nothing better when I try to debug locally.

1

There are 1 best solutions below

0
SaiVamshiKrishna On

Here is the way i am able to hit a SignalR ServerlessHub method

Step-1: Create an Azure Functions project

Step-2: Make sure your Azure Functions project is configured properly to use SignalR. The SignalR service connection string should be stored in your configuration. In the local.settings.json file for local development

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "AzureSignalRConnectionString": "YOUR_SIGNALR_CONNECTION_STRING"
  }
}

Step-3: Create Your SignalR Hub

    using Microsoft.Azure.Functions.Extensions.DependencyInjection;
    using Microsoft.Azure.WebJobs.Extensions.SignalRService;
    
    [assembly: FunctionsStartup(typeof(SignalRFunctionApp.Startup))]
    
    namespace SignalRFunctionApp
    {
        public class TestHub : ServerlessHub
        {
            [FunctionName("negotiate")]
            public SignalRConnectionInfo Negotiate(
                [HttpTrigger(AuthorizationLevel.Anonymous)] HttpRequest req)
            {
                var connectionInfo = Negotiate(req.Headers["x-ms-signalr-user-id"]);
                return connectionInfo;
            }
    
            [FunctionName("SendMessage")]
            public async Task SendMessage(
                [SignalRTrigger] InvocationContext invocationContext, string message, ILogger log)
            {
                log.LogInformation($"Received message: {message} from {invocationContext.ConnectionId}");
                await Clients.All.SendAsync("ReceiveMessage", message);
            }
        }
    }

Step-4: Add Required Packages

<ItemGroup>
  <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.SignalRService" Version="2.0.0" />
</ItemGroup>

Step-5: Client Code You can use a simple HTML/JavaScript client to connect to your SignalR hub.

<!DOCTYPE html>
<html>
<head>
    <title>SignalR Client</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/3.1.9/signalr.min.js"></script>
</head>
<body>
    <input type="text" id="userInput" />
    <button onclick="sendToServer()">Send Message</button>

    <script>
        const connection = new signalR.HubConnectionBuilder()
            .withUrl("/api/negotiate")
            .configureLogging(signalR.LogLevel.Information)
            .build();

        connection.on("ReceiveMessage", (message) => {
            console.log("Received message from server: " + message);
        });

        async function sendToServer() {
            const userInput = document.getElementById("userInput");
            try {
                // Check if the connection is in the "Connected" state
                if (connection.state === signalR.HubConnectionState.Connected) {
                    console.log("[Client.SignalR.SendMessage] " + userInput.value);
                    await connection.invoke("SendMessage", userInput.value);
                } else {
                    console.error("Connection is not in the 'Connected' state.");
                }
            } catch (err) {
                console.error(err);
            }
        }

        connection.start()
            .then(() => {
                console.log("Connected to the SignalR hub");
            })
            .catch((error) => {
                console.error(`Error connecting to the hub: ${error}`);
            });
    </script>
</body>
</html>

Verify the Connection State:

Before invoking the "SendMessage" method, ensure that the SignalR connection is in the "Connected" state. You can use the state property of the connection to check the current state and ensure it's connected before sending a message

Result enter image description here