Connect to Websockets using C# for WPF app

jmiller1213 years ago

I'm attempting to create a C# WPF app that (in part) connects to the Traccar Websockets API and receives the positions of my devices real-time. I'm essentially trying to mimic what the "Simple Web" example does here (https://github.com/traccar/traccar-web/blob/master/web/simple/app.js) where my app connects to the server, gets the list of devices, and then listens for the real-time feed from the server. I've been able to get to the point where I can retrieve the list of devices, but then I need to connect to the Websocket API (/api/socket) and I'm essentially clueless on how to do that. As stated in the documentation (https://www.traccar.org/traccar-api/) it says that "Session cookie is the only authorization option for WebSocket connection", and in a post here (https://www.traccar.org/forums/topic/use-websocket-in-traccaar-server/) Anton mentions that "You need to pass authentication cookie in the header when you open socket." Similar info in this post... (https://www.traccar.org/forums/topic/connecting-to-websockets-using-session-cookies/) Unfortunately I don't really know how to do that in C# (or really any language), so curious to know if someone would have an idea of how to do this...(with specific C# code...) Here is what I have so far...

private async Task ConnectToServer()
{
    string uri = "http://<My Server IP>:8082";
    string token = "<My Token>";
    
    try
    {
        HttpClient client = new HttpClient();
        
        var response1 = await client.GetAsync($"http://{uri}/api/session?token={token}");

        var response2 = await client.GetAsync($"http://{uri}/api/devices");

        var json = await response2.Content.ReadAsStringAsync();

        var devices = JsonConvert.DeserializeObject<List<Device>>(json);

        Uri myUri = new Uri($"ws://{uri}/api/socket");
        ClientWebSocket socket = new ClientWebSocket();

        // Here is where my knowledge is lacking... 
        // I don't know how to "send the authentication cookie"...
        
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}

public class Device
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string UniqueId { get; set; }
    // Other fields as needed...
}
William Reynaga3 years ago
private async Task ConnectToServer()
{
    string uri = "http://<My Server IP>:8082";
    string token = "<My Token>";

    try
    {
        HttpClient client = new HttpClient();

        var response1 = await client.GetAsync($"http://{uri}/api/session?token={token}");

        var response2 = await client.GetAsync($"http://{uri}/api/devices");

        var json = await response2.Content.ReadAsStringAsync();

        var devices = JsonConvert.DeserializeObject<List<Device>>(json);

        Dictionary<string, IEnumerable<string>> headers = null;

           headers = response1.Headers.ToDictionary(a => a.Key, a => a.Value);
            var datat = headers.Values.Where(m => m.FirstOrDefault().Contains("JSESSION")).FirstOrDefault().FirstOrDefault();
            var split_response = datat.Split(";");
            var response_fromsplit = split_response[0].Split("=");

        Uri myUri = new Uri($"ws://{uri}/api/socket");
        ClientWebSocket socket = new ClientWebSocket();
socket .SetCookie(new ClientWebSocket.Net.Cookie { Name= "JSESSIONID", Value = response_fromsplit[1] });

        // Here is where my knowledge is lacking... 
        // I don't know how to "send the authentication cookie"...

    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
    }
}

public class Device
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string UniqueId { get; set; }
    // Other fields as needed...
}
BerndFfm2 years ago

I just started to make my first steps with sockets. I use this Code, its working well in Xamarin Forms and ASP.NET Core :

        private async void Sockets_Start()
        {
            string sessionid = GetSessionId();
            if (sessionid == "") return;

            ClientWebSocket socket = new ClientWebSocket();
            socket.Options.Cookies = new System.Net.CookieContainer();
            socket.Options.Cookies.Add(new Uri(SocketServer()), new System.Net.Cookie("JSESSIONID", sessionid));
            await socket.ConnectAsync(new Uri(SocketServer()), System.Threading.CancellationToken.None);
            if (socket.State != WebSocketState.Open) return;

            WebSocketReceiveResult result;
            var buffer = new byte[65536];
            do
            {
                result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                string json = Encoding.UTF8.GetString(buffer, 0, result.Count);
                Socket soc = JsonConvert.DeserializeObject<Socket>(json);
                if (soc.devices != null) foreach (var dev in soc.devices) Socket_Device(dev);
                if (soc.positions != null) foreach (Position pos in soc.positions) Socket_Position(pos);
                if (soc.events != null) foreach (Event ev in soc.events) Socket_Event(ev);
            }
            while (!result.CloseStatus.HasValue);
            await socket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
        }

If you don't know how to get the SessionID let me know.

#Bernd

BerndFfm2 years ago

New code :

        private void Sockets_Start()
        {
            Thread thread = new Thread(SocketsStartAsync);
            thread.Start();
        }

        private async void SocketsStartAsync()	// #sockets
        {
            string sessionid = new clsTraccarApi().GetSessionId();
            if (sessionid == "")
            {
                Error("No connection to traccar server  !");
                return;
            }

            ClientWebSocket socket = new ClientWebSocket();
            socket.Options.Cookies = new System.Net.CookieContainer();
            socket.Options.Cookies.Add(new Uri(com.SocketServer()), new System.Net.Cookie("JSESSIONID", sessionid));
            await socket.ConnectAsync(new Uri(com.SocketServer()), System.Threading.CancellationToken.None);
            if (socket.State != WebSocketState.Open) return;

            _socket_close = false;
            WebSocketReceiveResult result;
            var buffer = new byte[128 * 1024];
            while (!_socket_close)
            {
                result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                string json = Encoding.UTF8.GetString(buffer, 0, result.Count);
                if (!json.EndsWith("}]}"))
                {
                    Thread.Sleep(100);
                    result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    json += Encoding.UTF8.GetString(buffer, 0, result.Count);
                }
                json = api.ConvertJson(json);
                Socket soc = JsonConvert.DeserializeObject<Socket>(json);
                if (soc.devices != null) for (int i = 0; i < soc.devices.Count; i++) Socket_Device(soc.devices[i]);
                if (soc.positions != null) for (int i = 0; i < soc.positions.Count; i++) Socket_Position(soc.positions[i]);
                if (soc.events != null) for (int i = 0; i < soc.events.Count; i++) Socket_Event(soc.events[i]);
            }
            await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Good Bye", CancellationToken.None);
        }