.NET Core SignalR with React Native

# .NET Core 2.2
#npm i @aspnet/signalr
#yarn add @aspnet/signalr

# .NET Core 3.0
npm install @microsoft/signalr

@microsoft/signalr works with .NET Core 3.1 and has a withAutomaticReconnect() function that we can use for reconnecting if connection lost. This makes code simpler. And it works with WebSocket by default so we don’t need the heartbeat either.

const connection = new SignalR.HubConnectionBuilder()
  .withUrl('https://api.mysite.com/signalhub', {
    accessTokenFactory: () => TOKEN
  })
  .configureLogging(SignalR.LogLevel.Debug)
  .withAutomaticReconnect() // this will reconnect if connection lost
  .build()

Working code example (@aspnet/signalr)

// App.tsx
import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import * as SignalR from '@aspnet/signalr'


export default function App() {
  const [connectionState, setConnectionState] = useState(false)
  const [connectionError, setConnectionError] = useState()
  useEffect(() => {
    signalr()
  }, []) // passing an empty array makes sure this only runs on mount/unmount and not everytime props/state changes. if you give it something inside the array it'll only update when that something updates

  function signalr() {
    // das function to start a connection with SignalR hub for our app
    const token = "mySuperSecretToken"
    const connection = new SignalR.HubConnectionBuilder()
      .withUrl('https://api.mysite.com/signalhub', {
        accessTokenFactory: () => token
      })
      .configureLogging(SignalR.LogLevel.Debug)
      .build()
  
    async function start() {
      try {
        await connection.start()
        setConnectionState(true)
        
        setInterval(() => {
          connection.invoke('heartbeat')
          console.log(`beat`)
        }, 15000) // Send heartbeat every 15 secs.
        setConnectionError('')
        console.log('CONNECT ho gya!')
      } catch (error) {
        console.error(`Disconnected with status code ${error.statusCode}`, JSON.stringify(error))
        setConnectionError(JSON.stringify(error))
        setTimeout(() => start(), 5000) // Retry connection after 5secs 
      }
    }
  
    // connection.serverTimeoutInMilliseconds = 3600000
    // connection.keepAliveIntervalInMilliseconds = 10000
    start()
  
    // Reconnect
    connection.onclose(async (error) => {
      setConnectionState(false)
      setConnectionError(JSON.stringify(error))
      console.log('awwww =( chala gya')
      console.error(`Disconnected with status code ${error.statusCode}`, JSON.stringify(error))
      await start()
    })
    
    // Listen for events
    connection.on('messageReceived', (data) => {
      console.log(`\n data: \n ${JSON.stringify(data, null, '\t')} \n`)
    })

    connection.on('notificationReceived', (data) => {
      console.log(`\n data: \n ${JSON.stringify(data, null, '\t')} \n`)
    })
  }

  
  return (
    <View style={styles.container}>
      <Text>
        You are <Text style={styles.boldText}>{connectionState ? <Text style={styles.greenText}>connected</Text> : <Text style={styles.redText}>disconnected</Text>}</Text>
        <Text>{connectionError ? connectionError : null }</Text>
      </Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
  boldText: {
    fontWeight: 'bold'
  },
  greenText: {
    color: '#2ECC71',
  },
  redText: {
    color: '#E74C3C'
  }
});

Notes

  • You need to invoke something at regular intervals in order to stay connnected. Otherwise it’ll timeout the connection every 3060 secs..
  • Doesn’t matter if the method you’re invoking exists. If it doesn’t, you’ll get a HubException error about method not existing, but you’ll stay connected nonetheless.
  • i have tried setting the keepAliveIntervalInMilliseconds and serverTimeoutInMilliseconds values on the frontend but that didn’t work
  • The { accessTokenFactory: () => token } bit alllows you to pass a token for authorization.
  • There are different LogLevels. Debug will give you more details