Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Once the negotiate function is hit i'm still not able to connect to the instance of signalR #1799

Open
Vikas252 opened this issue Jun 21, 2023 · 3 comments
Labels
pending-customer-confirmation Suggestions provided, waiting for the customer's confirmation

Comments

@Vikas252
Copy link

Describe the bug

i'm using signalR instance (serverless mode) i have created the bindings for signalR through the serverless framework, once the negotiate route is been hit i get the response but further when i try to connect with the same url and access token received from the negotiate function it gives error of HubConnection failed to start successfully because of error 'Error: Failed to complete negotiation with the server: TypeError: Cannot read properties of undefined (reading 'secure')'.

To Reproduce

function.json:

{
  "disabled": false,
  "bindings": [
    {
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "route": "negotiate",
      "authLevel": "function",
      "methods": ["POST"]
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    },
    {
      "type": "signalRConnectionInfo",
      "name": "connectionInfo",
      "hubName": "serverless",
      "connectionStringSetting": "AzureSignalRConnectionString",
      "direction": "in"
    }
  ],
  "entryPoint": "negotiate",
  "scriptFile": "../dist/server.js"
}

Azure function handler (Number 1) i.e server.ts:

module.exports.negotiate = async (context, req, connectionInfo) => {
  console.log(connectionInfo, 'Serverless-signalR');
  const connection = new HubConnectionBuilder()
    .withUrl(`${connectionInfo.url}`, {
      accessTokenFactory: () =>
        `${connectionInfo.accessToken}`,
      // skipNegotiation: true,
      transport: HttpTransportType.WebSockets
    }).withAutomaticReconnect().configureLogging(LogLevel.Debug)
    .build();
  connection.start();
  context.res.body = connectionInfo;
};

Azure function handler (Number 2) i.e server.ts:

module.exports.negotiate = async (context, req, connectionInfo) => {
  console.log(connectionInfo, 'Serverless-signalR');
  // const connection = new HubConnectionBuilder()
  //   .withUrl(`${connectionInfo.url}`, {
  //     accessTokenFactory: () =>
  //       `${connectionInfo.accessToken}`,
  //     // skipNegotiation: true,
  //     transport: HttpTransportType.WebSockets
  //   }).withAutomaticReconnect().configureLogging(LogLevel.Debug)
  //   .build();
  // connection.start();
  context.res.body = connectionInfo;

Serverless.yml specification:

negotiate:
    handler: dist/server.negotiate
    events:
      - http: true
        route: negotiate
        methods:
          - POST
    outputs:
      connectionInfo:
        type: signalRConnectionInfo
        name: connectionInfo
        hubName: serverless
        connectionStringSetting: AzureSignalRConnectionString
        direction: in

app.ts:

import express from 'express';
import cors from 'cors';
import helmet from 'helmet';

const app = express();
app.use(helmet({
  xFrameOptions: { action: 'deny' },
}));
app.set('port', process.env.PORT || 3000);
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cors());

async function main() {
  try {
    app.listen(app.get('port'), () => console.log(`listening on port ${app.get('port')}`));
} catch (err) {
    console.error(err);
  }
}
main();

Exceptions (if any)

If azure handler is Number 1:

Executing 'Functions.negotiate' (Reason='This function was programmatically called via the host APIs.', Id=*****-****-****-*****)
Debug: Starting HubConnection.
Debug: Starting connection with transfer format 'Text'.
Sending negotiation request: https:/<base_url>/client/negotiate?hub=serverless&negotiateVersion=1.
Warning: Error from HTTP request. TypeError: Cannot read properties of undefined (reading 'secure').
Error: Failed to complete negotiation with the server: TypeError: Cannot read properties of undefined (reading 'secure')

If azure handler is Number 2

Executing 'Functions.negotiate' (Reason='This function was programmatically called via the host APIs.', Id=6057257d-f7d1-423f-b6dd-15a2d2f0968f)
[2023-06-21T08:05:26.009Z] {
[2023-06-21T08:05:26.011Z]   url: 'https://<base_url>/client/?hub=serverless',
[2023-06-21T08:05:26.012Z]   accessToken: '<token>'
[2023-06-21T08:05:26.014Z] } Serverless-signalR
[2023-06-21T08:05:26.224Z] Executed 'Functions.negotiate' (Succeeded, Id=6057257d-f7d1-423f-b6dd-15a2d2f0968f, Duration=426ms)

Further technical details

"azure-functions-core-tools": "^4.0.5148",
"@microsoft/signalr": "^7.0.7",

@vicancy
Copy link
Member

vicancy commented Jun 26, 2023

Where do you expect to start the connection? In Number1 looks like you are trying to start the connection from inside the Negotiate function. Could you describe your scenario a little bit more?

@Vikas252
Copy link
Author

Vikas252 commented Jun 26, 2023

@vicancy Thank you for the response the scenario can be like
The system is built on nodejs with express multiple express routes, consist of handlers for different routes on of them is the negotiate route through which the signalR connection end point URL and access Token is obtained

I need to access or open websocket mode for serverless on a particular page when the user clicks maybe a different route, to communicate with my angular frontend so to connect the signalR in my backend when i get the connection endpoint and access token i have a controller which handles the connection for signalR so there i create a new connection with the existing json i received from the negotiate function called.

When tried with the controller it says
Error from HTTP request. TypeError: Cannot read properties of undefined (reading 'secure').

For the response of negotiate function i called it explicitly from postman for testing in the above scenario

@vicancy
Copy link
Member

vicancy commented Jun 30, 2023

I did a quick try on creating a negotiate function and it is successfully connected locally using the latest core tool version 4.0.5198. Here is my steps:

  1. open a codespace from https://github.com/aspnet/AzureSignalR-samples
  2. In the codespace terminal install func npm i -g azure-functions-core-tools
  3. under folder samples/QuickStartServerless/javascript
    1. Rename local.settings.template.json to local.settings.json
    2. Update AzureSignalRConnectionString to your Azure SignalR connection string
    3. Remove other subfolders and only keep folder negotiate (to avoid other dependencies)
  4. In terminal run npm i --save @microsoft/signalr
  5. Update negotaite/index.js to
    const { HubConnectionBuilder, HttpTransportType, LogLevel } = require("@microsoft/signalr");
    module.exports = async function (context, req, connectionInfo) {
      const connection = new HubConnectionBuilder()
        .withUrl(`${connectionInfo.url}`, {
          accessTokenFactory: () => `${connectionInfo.accessToken}`,
          transport: HttpTransportType.WebSockets
        })
        .withAutomaticReconnect()
        .configureLogging(LogLevel.Debug)
        .build();
    
      console.log(connectionInfo);
      await connection.start();
    
      context.res.body = connectionInfo;
    };
  6. In terminal run func start
  7. Start another terminal run curl -X POST http://localhost:7071/api/negotiate
  8. The logs show Debug: HubConnection connected successfully.
    image

@vicancy vicancy added the pending-customer-confirmation Suggestions provided, waiting for the customer's confirmation label Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pending-customer-confirmation Suggestions provided, waiting for the customer's confirmation
Projects
None yet
Development

No branches or pull requests

2 participants