Signalr .net client

3.1k views Asked by At

So im try to connect to a service in c#, i have no control over this service and cant change anything there, and nor do i have any documentation to help :(

so what im trying to do is change this JavaScript SignalR client to .net (But not all of it)

    $(document).ready(function () {

        //URL of the queues api
        var queueApi = "/CCMWa/api/v1/queues/";

        //SignalR connection
        $.connection.hub.logging = true;
        var myHub = $.connection.queueStatistics;

        //Wire event handlers
        myHub.client.onQueueNowDataUpdate = function (data) {
            //alert(data);
            var data = JSON.stringify(data);
            $('#messages').append('<li>Server: Received onQueueNowDataUpdate</li>');
            $('#getNowResults').text(data);
        };

        //Wire event handlers
        myHub.client.onQueueConversationUpdate = function (data) {
            //alert(data);
            var data = JSON.stringify(data);
            $('#messages').append('<li>Server: Received onQueueConversationUpdate</li>');
            $('#getConversationResults').text(data);
        };

        //Wire event handlers
        myHub.client.connected = function () {
            $('#messages').append('<li>Server: Says we are Connected</li>');                
        };

        //Wire event handlers
        myHub.client.reconnected = function () {
            $('#messages').append('<li>Server: Says we are Reconnected</li>');
        };

        //Start
        $.connection.hub.start()
                        .done(function () {
                            logMessage("Client: Connection Started");
                            //myHub.server.joinFoo()
                            //     .done(function () {
                            //         logMessage("Client: Sent Join to Server");
                            //     })
                        })
                        .fail(function () {
                            logMessage("Client: Could not connect to server");
                        });

        $("#startNow").click(function () {
            var id = $("#queueNowId").val();

            myHub.server.startQueueStateMonitor(id)
               .done(function () {
                   $('#messages').append('<li>Client: addMonitor for ' + id + '</li>');
               })
               .fail(function () {
                   $('#messages').append('<li>Client: failed to send addMonitor</li>');
               });

        });

        function logMessage(message)
        {
            $('#messages').append(message);
        }

        $("#stopNow").click(function () {
            var id = $("#queueNowId").val();

            myHub.server.stopQueueStateMonitor(id)
               .done(function () {
                   $('#messages').append('<li>Client: removeMonitor for ' + id + '</li>');
               })
               .fail(function () {
                   $('#messages').append('<li>Client: failed to send removeMonitor</li>');
               });
        });

        $("#getAll").click(function () {
            var uri = queueApi;
            //alert(uri);
            $.get(uri,
                function (items) {
                    data = JSON.stringify(items);
                    $("#getAllResults").text(data);
                });                
        });

        $("#getDetails").click(function () {
            var id = $("#queueDetailsId").val();
            var uri = queueApi + id;
            //alert(uri);
            $.get(uri,
                function (items) {
                    data = JSON.stringify(items);
                    $('#getDetailsResults').text(data);
                });
        });           

        $("#getNow").click(function () {
            var id = $("#queueNowId").val();
            var uri = queueApi + id + "/now";
            //alert(uri);
            $.get(uri,
                function (items) {
                    data = JSON.stringify(items);
                    $('#getNowResults').text(data);
                });
        });


        $("#startConversationMonitor").click(function () {
            var id = $("#queueConversationsId").val();

            myHub.server.startQueueConversationMonitor(id)
               .done(function () {
                   $('#messages').append('<li>Client: addMonitor for ' + id + '</li>');
               })
               .fail(function () {
                   $('#messages').append('<li>Client: failed to send addMonitor</li>');
               });
        });


        $("#stopConversationMonitor").click(function () {
            var id = $("#queueConversationsId").val();

            myHub.server.stopQueueConversationMonitor(id)
               .done(function () {
                   $('#messages').append('<li>Client: removeMonitor for ' + id + '</li>');
               })
               .fail(function () {
                   $('#messages').append('<li>Client: failed to send removeMonitor</li>');
               });
        });

        $("#getConversations").click(function () {
            var id = $("#queueConversationsId").val();
            var uri = queueApi + id + "/conversations";
            //alert(uri);
            $.get(uri,
                function (items) {
                    data = JSON.stringify(items);
                    $('#getConversationResults').text(data);
                });
        });
    });       

Here is what i have currently in c#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client;
using Microsoft.AspNet.SignalR.Client.Hubs;

namespace ConsoleApplication3
{
class Program
{
    static void Main(string[] args)
    {
        //Set connection
        var connection = new HubConnection("http://servername/CCMWa/");
        connection.TraceLevel = TraceLevels.All;
        connection.TraceWriter = Console.Out;

        //Make proxy to hub based on hub name on server
        var myHub = connection.CreateHubProxy("queueStatistics");

        //Start connection


        connection.Start().ContinueWith(task => {
            if (task.IsFaulted) {
                Console.WriteLine("There was an error opening the connection:{0}",
                                  task.Exception.GetBaseException());
            } else {
                Console.WriteLine("Connected");
            }

        }).Wait();

        myHub.Invoke<string>("startQueueStateMonitor", "445cb4e7-88a7-47d4-bb13-e8b40854f4a5").ContinueWith(task =>
        {
            if (task.IsFaulted) {
                Console.WriteLine("There was an error calling send: {0}",
                                  task.Exception.GetBaseException());
            } else {
                Console.WriteLine("hello");     
                Console.WriteLine(task.Result);                  
            }
        });


        myHub.On("connected", () => Console.WriteLine(" server said connected"));

        myHub.On<string>("onQueueNowDataUpdate", data => { Console.WriteLine(data); });

        //myHub.On<string>("onQueueConversationUpdate", data => { Console.WriteLine(data); });


        Console.Read();
        connection.Stop();
    }
    }
}

and here is its output

            08:10:06.4207699 - null - ChangeState(Disconnected, Connecting)                 

            08:10:06.7977915 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - SSE: GET http://servername/CCMWa/signalr/connect?transport=serverSentEvents&connectionToken=n6c1mQ6E22kyyqrALVJ2LK2nlWqKQbFZmJOLs9flk75jhvbwPPddp5wGcBMg_9VGeXtWLlqmjETWUaT_de8KLiODqxZG3ZAa6KzHqM9Ik4cuS0CuWnz8YspN79wPsF3l0&connectionData=[{"Name":"queueStatistics"}]                 

            08:10:06.8617951 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - ChangeState(Connecting, Connected) Connected              

            08:10:06.8667954 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - SSE: OnMessage(Data: initialized)                 
            08:10:07.0518060 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - OnMessage({"I":"0"}) hello                
            08:10:07.1168097 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - SSE: OnMessage(Data: {"C":"Gg,0|Ix,1|Iy,0|Iz,0","M":[{"H":"queueStatistics","M":"connected","A":[]}]})  server said connected                 08:10:07.1328106 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - SSE: OnMessage(Data: {"C":"Gg,0|Ix,1|Iy,1|Iz,0|Hf,13A2","G":"JbB1ER_V5dMWm0Cxe5LFQluULoB69DHmULrH6WM_nM2Dbsk-y-qGne7GwpaUSUlSfdS1KNUjuVgU-Femd 3IucV56Iw545IKDvlxNXL7pmdcGtvZbAIjMKIjXbEdTLSMAkxGGJZDhr4nD4KWzpHMQtA2","M":[]})               08:10:07.1338107 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - SSE: OnMessage(Data: {"C":"Gg,0|Ix,2|Iy,1|Iz,0|Hf,13A2","M":[{"H":"queueStatistics","M":"onQueueNowDataUpdate","A":[{"configData":{"Id":"445cb 4e7-88a7-47d4-bb13-e8b40854f4a5","Name":"Dutch","Reporting":"P503","MediaType":0,"MediaServer":null,"MediaServerId":"00000000-0000-0000-0000-000000000000","NowStatisticsUrl":null,"StatisticsHubName":" queueStatistics","Links":[],"Url":null},"Status":"ACD","LongestWaiting":0.0,"Acd":0,"NonAcd":0,"Out":0,"Unavailable":1,"Offered":3,"Handled":3,"Abandoned":0,"Interflow":0,"Requeue":0,"ServiceLevel":10 0,"AgentsIdle":2,"ItemsWaiting":0,"QueueOpen":false,"AgentsLoggedIn":0,"AgentsAvailable":2,"EstimatedWaitTime":0.0,"AverageHandlingTime":0,"DetailsUrl":null}]}]})               

            08:10:07.1878138 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - OnError(Newtonsoft.Json.JsonReaderException: Error reading string. Unexpected token: StartObject. Path ''.    at Newtonsoft.Json.JsonReader.ReadAsStringInternal()    at Newtonsoft.Json.Linq.JTokenReader.ReadAsString()    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)    at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)    at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)    at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)    at Newtonsoft.Json.Linq.JToken.ToObject[T](JsonSerializer jsonSerializer)    at Microsoft.AspNet.SignalR.Client.Hubs.HubProxyExtensions.Convert[T](JToken obj, JsonSerializer serializer)    at Microsoft.AspNet.SignalR.Client.Hubs.HubProxyExtensions.<>c__DisplayClass6`1.<On>b__4(IList`1 args)    at Microsoft.AspNet.SignalR.Client.Hubs.Subscription.OnReceived(IList`1 data)    at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.InvokeEvent(String eventName, IList`1 args)    at Microsoft.AspNet.SignalR.Client.Hubs.HubConnection.OnMessageReceived(JToken message)    at Microsoft.AspNet.SignalR.Client.Connection.Microsoft.AspNet.SignalR.Client.IConnection.OnReceived(JToken message)    at Microsoft.AspNet.SignalR.Client.Transports.TransportHelper.ProcessResponse(IConnection connection, String response, Boolean& timedOut, Boolean& disconnected))              

            08:10:08.0928655 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - SSE: OnMessage(Data: {"C":"Gg,0|Ix,2|Iy,1|Iz,0|Hf,13A3","M":[{"H":"queueStatistics","M":"onQueueNowDataUpdate","A":[{"configData":{"Id":"445cb 4e7-88a7-47d4-bb13-e8b40854f4a5","Name":"Dutch","Reporting":"P503","MediaType":0,"MediaServer":null,"MediaServerId":"00000000-0000-0000-0000-000000000000","NowStatisticsUrl":null,"StatisticsHubName":" queueStatistics","Links":[],"Url":null},"Status":"ACD","LongestWaiting":0.0,"Acd":0,"NonAcd":0,"Out":0,"Unavailable":1,"Offered":3,"Handled":3,"Abandoned":0,"Interflow":0,"Requeue":0,"ServiceLevel":10 0,"AgentsIdle":2,"ItemsWaiting":0,"QueueOpen":false,"AgentsLoggedIn":0,"AgentsAvailable":2,"EstimatedWaitTime":0.0,"AverageHandlingTime":0,"DetailsUrl":null}]}]})               

            08:10:08.1308677 - 66fd7caa-b3f8-4297-9c83-5a2dd5c9e72e - OnError(Newtonsoft.Json.JsonReaderException: Error reading string. Unexpected token: StartObject. Path ''.    at Newtonsoft.Json.JsonReader.ReadAsStringInternal()    at Newtonsoft.Json.Linq.JTokenReader.ReadAsString()    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ReadForType(JsonReader reader, JsonContract contract, Boolean hasConverter)    at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)    at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)    at Newtonsoft.Json.JsonSerializer.Deserialize(JsonReader reader, Type objectType)    at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)    at Newtonsoft.Json.Linq.JToken.ToObject[T](JsonSerializer jsonSerializer)    at Microsoft.AspNet.SignalR.Client.Hubs.HubProxyExtensions.Convert[T](JToken obj, JsonSerializer serializer)    at Microsoft.AspNet.SignalR.Client.Hubs.HubProxyExtensions.<>c__DisplayClass6`1.<On>b__4(IList`1 args)    at Microsoft.AspNet.SignalR.Client.Hubs.Subscription.OnReceived(IList`1 data)    at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.InvokeEvent(String eventName, IList`1 args)    at Microsoft.AspNet.SignalR.Client.Hubs.HubConnection.OnMessageReceived(JToken message)    at Microsoft.AspNet.SignalR.Client.Connection.Microsoft.AspNet.SignalR.Client.IConnection.OnReceived(JToken message)    at Microsoft.AspNet.SignalR.Client.Transports.TransportHelper.ProcessResponse(IConnection connection, String response, Boolean& timedOut, Boolean& disconnected))` 

Can any offer any guidance to what im doing wrong here

1

There are 1 answers

3
Jon Egerton On BEST ANSWER

Not 100% on this without running it myself but:

I think the problem is your debugging line:

myHub.On<string>("onQueueNowDataUpdate", data => { Console.WriteLine(data); });

This line is treating the incoming message as a string, except that the data isn't a string as it's a serialized object.

ie what's in the data is the part that looks the following in the trace (with M denoting the message body I think):

 "M": [
            {
                "H": "queueStatistics",
                "M": "onQueueNowDataUpdate",
                "A": [
                    {
                        "configData": {

The Json deserializer wants something like

 "M": "Foobar"

Really you need a class declaration that matches the incoming message (appreciate that's probably what you're going to write next).

Update for class generation:

Simplest think to generate a class from Json is to let some-one else do it for you. If you paste the message (disregard the "M:[" part) into json2csharp.com:

            {
                "H": "queueStatistics",
                "M": "onQueueNowDataUpdate",
                "A": [
                    {
                        "configData": {
                            "Id": "445cb 4e7-88a7-47d4-bb13-e8b40854f4a5",
                            "Name": "Dutch",
                            "Reporting": "P503",
                            "MediaType": 0,
                            "MediaServer": null,
                            "MediaServerId": "00000000-0000-0000-0000-000000000000",
                            "NowStatisticsUrl": null,
                            "StatisticsHubName": " queueStatistics",
                            "Links": [

                            ],
                            "Url": null
                        },
                        "Status": "ACD",
                        "LongestWaiting": 0.0,
                        "Acd": 0,
                        "NonAcd": 0,
                        "Out": 0,
                        "Unavailable": 1,
                        "Offered": 3,
                        "Handled": 3,
                        "Abandoned": 0,
                        "Interflow": 0,
                        "Requeue": 0,
                        "ServiceLevel": 100,
                        "AgentsIdle": 2,
                        "ItemsWaiting": 0,
                        "QueueOpen": false,
                        "AgentsLoggedIn": 0,
                        "AgentsAvailable": 2,
                        "EstimatedWaitTime": 0.0,
                        "AverageHandlingTime": 0,
                        "DetailsUrl": null
                    }
                ]
            }
        

You get:

public class ConfigData
{
    public string Id { get; set; }
    public string Name { get; set; }
    public string Reporting { get; set; }
    public int MediaType { get; set; }
    public object MediaServer { get; set; }
    public string MediaServerId { get; set; }
    public object NowStatisticsUrl { get; set; }
    public string StatisticsHubName { get; set; }
    public List<object> Links { get; set; }
    public object Url { get; set; }
}

public class A
{
    public ConfigData configData { get; set; }
    public string Status { get; set; }
    public double LongestWaiting { get; set; }
    public int Acd { get; set; }
    public int NonAcd { get; set; }
    public int Out { get; set; }
    public int Unavailable { get; set; }
    public int Offered { get; set; }
    public int Handled { get; set; }
    public int Abandoned { get; set; }
    public int Interflow { get; set; }
    public int Requeue { get; set; }
    public int ServiceLevel { get; set; }
    public int AgentsIdle { get; set; }
    public int ItemsWaiting { get; set; }
    public bool QueueOpen { get; set; }
    public int AgentsLoggedIn { get; set; }
    public int AgentsAvailable { get; set; }
    public double EstimatedWaitTime { get; set; }
    public int AverageHandlingTime { get; set; }
    public object DetailsUrl { get; set; }
}

public class RootObject
{
    public string H { get; set; }
    public string M { get; set; }
    public List<A> A { get; set; }
}

You should change the name of RootObject to something that makes more sense to you. Also note that obviously this only knows about properties that are in the original Json, so you should do it with the most complex version of the message you'll be receiving so that you can so you don't miss anything out.

Then you can pick up the class instance with (pretty much as you would with the JS version):

myHub.On<RootObject>("onQueueNowDataUpdate", data => { <<Do something with RootData instance here>> });