0

I am trying to implement request/response paradigm for Websocketsharp library exactly same it works for HttpClient's request/response async behavior. I am trying to achieve it using the async callback as given in below code. I tried to get SendAsync method's OnMessage callback event to wait until the server sends the response. I am able to get the response within the scope of the SendAsync method but as soon as we come out of SendAsync scope it clears out the value of the response.

string clientResponse = null;

            var response = Task.Run(() => objWSClient.SendAsync(stream, Convert.ToInt32(stream.Length), (async (completed) =>
            {
                if (completed)
                {
                    clientResponse = await WSMessageSendSuccess(reqObject, callback);

                    // Websocket response is flushed to the console window, but when it leaves the scope, it doesn't hold the response out of the SendAsync() scope.
                    Console.WriteLine(clientResponse);
                }
                else
                {
                    WSMessageSendFail(reqObject);
                    clientResponse = "Failure to send Message";
                }
            })));


            while (response.Status != TaskStatus.RanToCompletion)
            {
                Task.Delay(10000).Wait();
            }
            response.Wait();

            // As soon as we leave scope of WebSocket.SendAsync() method, it clears the client response variable value.
            // variable name : clientResponse;, it also works same with static property/variable.
            return clientResponse;
ajay_whiz
  • 17,573
  • 4
  • 36
  • 44
Jits
  • 712
  • 7
  • 11
  • You can encapsulate the API by following Microsoft's article, https://learn.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop-with-other-asynchronous-patterns-and-types#tasks-and-the-event-based-asynchronous-pattern-eap – Lex Li Sep 22 '17 at 15:21

1 Answers1

2
static Class WSClient{


        Private Dictionary <string, Func<string, void>> DictWSReqResp = new Dictionary <string, Func<string, void>>();
        Private WebSocket objWSClient;


        public static void init(Iconfiguration config){
            //instantiate objWSClient here, set all handlers, and connect
            objWSClient.OnMessage += new EventHandler<MessageEventArgs>(e_ServerMessageReceived);
        }




        async Task<String> Request(uri, method, payload, headers){

            //it is important that this be an async function and the return be an await, because this way we 
            //guarantee that the taskCS remains in scope of this function. If this were to return the task itself
            //then the tcs will be subject to GC.

            //the three variables below will remain alive while the task is not completed
            TaskCompletionSource<string> taskCS = new TaskCompletionSource<string>();
            string trackid = trackid;
            Action<string> callback;

            //the sendAsync callback should NOT be async
            objWSClient.SendAsync(stream, Convert.ToInt32(stream.Length), new Action<bool>(completed) =>
            {
                if (completed)
                {
                    callback = (payload)=>{ //this will not run unless called by the e_ServerMessageReceived handler
                        taskCS.SetResult(payload);
                        DictWSReqResp.delete(trackid);
                    }
                    DictWSReqResp.Add(trackid, callback);
                }
                else
                {
                    //create well formed errorPayload
                    taskCS.SetException(errorPayload);
                }
            });



            return await taskCS.Task;


        }



        private static void e_ServerMessageReceived(payload){ //server sends {t:1 /*for responses*/, i:<trackid>, p:<response payload>}
            if(t==1)(DictWSReqResp(payload.i))(payload.p);

        }

    }
Yoel Kohn
  • 21
  • 4
  • Sorry for the ugliness. This is my solution for much the same problem as yours. The server response is a JSON object with payload.i set to the trackid. The rest is self explanatory. – Yoel Kohn Sep 25 '17 at 20:42
  • There's also a bit of logic missing. My class converts a REST message to a WS payload. – Yoel Kohn Sep 25 '17 at 20:56