Connect to Websockets using C# for WPF app

jmiller1214 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 Reynaga4 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...
}
BerndFfm3 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

BerndFfm3 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);
		}
Vinod8 months ago

@BerndFfm Can you help me with the code for api.convertJson and definition for soc device, position and events class. Thanks

                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]);