Dan Ugore
Dan Ugore

Reputation: 21

How do I catch a MissingMethodException for ASP.NET SignalR Hub?

I have successfully connected a simple js client to my server using the @microsoft/signalr library. However whenever I try to use the send() or invoke() methods on the client, the connection is terminated due to a MissingMethodException supposedly thrown by the server. My debugger never catches this exception and I have no idea where a try-catch block would go to catch it myself.

I have tried various casing to match the method name (Camel, Pascal, Upper, Lower) and none have worked. I have tried updating the method to return values that are not void and that also has not worked.

The Hub code

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.SignalR.Protocol;

namespace GCGSite.Server
{
    public class MessageHub : Hub
    {
        public async Task SendMessage(string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }
}

The Client code calling send.

    async function sendMessage(msg) {
        console.log("Attempting send: ", msg);
        if (connection.state === "Connected") {
            // SendMessage returns void but if the method were to return something it would come back as res
            let res = await connection.invoke("SendMessage", "Test")
                .catch(err => console.log("Send erred", err));
        }
    }

The Client in full

import { useEffect, useState } from 'react';
import { HubConnectionBuilder, HubConnectionState } from '@microsoft/signalr';
import './App.css';

const connection = new HubConnectionBuilder()
    .withUrl("https://localhost:7263/chathub")
    .build();
connection.logging = true;
console.log(connection);

function App() {
    const [logs, setLogs] = useState([]);
    const [connected, setConnected] = useState(false);

    return (
        <div>
            <div>
                <h1>Log</h1>
                <div className="chatlog">
                    { logs.map(msg => <div>{msg}</div>) }
                </div>
                <input id="chatinput" className="chatinput"></input><button onClick={ async (e) => await sendButtonHandler(e) }>Send</button><button disabled={connected} onClick={async () => await connectWS()}>Connect</button>
            </div>
        </div>
    );
    
    async function connectWS() {
        console.log("Connect Clicked");
        if (!connected) {
            await connection.start()
                .catch(err => console.error('Error connecting to hub:', err));
            if (connection.state === HubConnectionState.Connected) {
                console.log('Connected to SignalR hub');
                setConnected(true);

                connection.onclose(() => {
                    setConnected(false);
                    setLogs([...logs, "Connection Died"]);
                    console.log("Connection down: Run on close events");
                })

                connection.on('ReceiveMessage', message => {
                    console.log('Received message:', message);
                    setLogs([...logs, message]);
                    console.log('log history', logs);
                });
            }
        }
        else {
            console.log("Already connected to server");
        }
    }

    async function sendButtonHandler(e) {
        var el = document.getElementById("chatinput");
        var text = el.value;
        el.value = "";
        await sendMessage(text);
    }

    async function sendMessage(msg) {
        console.log("Attempting send: ", msg);
        if (connection.state === "Connected") {
            // SendMessage returns void but if the method were to return something it would come back as res
            let res = await connection.invoke("SendMessage", "Test")
                .catch(err => console.log("Send erred", err));
        }
    }
}

export default App;

Upvotes: 2

Views: 39

Answers (0)

Related Questions