Search code examples
c#kotlinwebsockethttpclientdesktop-application

What is the equivalent of Kotlin WebSocketSession object in c#?


For a few months now I have been using the ktor framework to create servers that expose rest calls and communication via webSockets. For now I have always used clients using kotlin as a programming language (or Android App, or App Desktop).

Specifically, I had a class that was injected with the HttpClient object (from the documentation = Asynchronous client to perform HTTP requests).

Within this class I have 4 methods:

  1. start the session: instantiate the WebSocketSession object (Represents a web socket session between two peers)
  2. send Frame
  3. receives Frame
  4. close the session

In Ktor my class is something that looks a lot like this:

class WebSocketServiceImpl(
    private val client: HttpClient
){

private var socket: WebSocketSession? = null

//1)
suspend fun initSession(username: String): Resource<Unit>{
   socket = client.webSocketSession {
                url("ws://xxx.xxx.xxx.xxx:xxxx/myRoute?username=$username")
}

//2)
suspend fun send(myObj: MyObj) {
        try {
            val myObjSerialized = Json.encodeToString(myObj)
            socket?.send(Frame.Text(myObjSerialized ))
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

//3)
fun observePrintableMessages(): Flow<MyObj> {
        return try {
            socket?.incoming
                ?.receiveAsFlow()
                ?.filter { it is Frame.Text }
                ?.map {
                    val myObjString = (it as? Frame.Text)?.readText() ?: ""
                    val printableMessageDto = Json.decodeFromString<MyObj>(myObjString)
                } ?: flow { }
        } catch (e: Exception) {
            e.printStackTrace()
            flow { }
        }
    }

//4)
suspend fun closeSession() {
        socket?.close()
    }

}

From the C # documentation instead, I found these examples on how to use Client-side WebSockets:


//1)
const exampleSocket = new WebSocket("wss://www.example.com/socketserver", "protocolOne");

//2)
exampleSocket.send("Here's some text that the server is urgently awaiting!");

//3)
exampleSocket.onmessage = (event) => {
  console.log(event.data);
}

//4)
exampleSocket.close();

Admitted and not granted that the methods I found in C # really work, to make the WebSocket object used in C # be equivalent to the WebSocketSession object in Kotlin is enough for me to do so? :


public void initSession(string username)
{
   exampleSocket = new WebSocket($"wss://www.example.com/socketserver?username={username}", "");
}


Or is it some other type of object to use?

If for any reason you don't know the answer, you don't need to vote negative, you can just move on.


Solution

  • I used the Websocket.Client library (by Mariusz Kotas) found on NuGet

    public class WebSocketService : IWebSocketService
    {
    
        public event EventHandler<MessageReceivedEventArgs> MessageReceived;
        private void FireMessageReceivedEvent(Message message) => MessageReceived?.Invoke(this, new MessageReceivedEventArgs(message));
    
        public string Url { get => "ws://192.168.1.202:8082/chat-socket"; }
    
        private WebsocketClient webSocketClient;
    
    
        public async Task<SessionResoult> InitSession(string username)
        {
            string usernameSession = $"?username={username}";
            string urlWithUsername = $"{Url}{usernameSession}";
            try
            {
                webSocketClient = new WebsocketClient(new Uri(urlWithUsername));
                await webSocketClient.Start();
                if (webSocketClient.IsRunning)
                {
                    SubscribeNewMessages();
                    return new SessionResoult.Success();
                }
                else
                {
                    return new SessionResoult.Error("webSocketClient is not running");
                }
            }
            catch(Exception ex)
            {
                return new SessionResoult.Error(ex.Message);
            }
            
           
        }
    
        private void SubscribeNewMessages()
        {
            webSocketClient.MessageReceived.Subscribe(m =>
            {
                MessageDto message = JsonConvert.DeserializeObject<MessageDto>(m.Text);
                FireMessageReceivedEvent(message.ToMessage());
            });
        }
    
        public async Task SendMessageAsync(string message)
        {
            
            await Task.Run(() => webSocketClient.Send(message));
        }
    
        public void CloseSession()
        {
            webSocketClient.Dispose();
        }
    
    
    }
    

    In the code, the interesting parts are:

    1) initialization of the WebsocketClient object

    2) the subscription of receiving messages ( Start() method immediately after initialization)

    3) observation of message subscription -> webSocketClient.MessageReceived.Subscribe

    4) the 'Fire' of the event linked to the observation of messages -> FireMessageReceivedEvent

    5) those who use the class must subscribe to the event of the latter ->

    webSocketService.MessageReceived + = (sender, e) => {OnMessageReceived (e.MessageReceived); };

    MessageReceivedEventArgs -> Class describing the Arguments of the event

    SessionResoult -> Class similar to an Enum but with the possibility of passing a string or not based on which subclass it is