locked
.Net Core API with UI needing to open a websocket connection question_ RRS feed

  • Question

  • User-544325736 posted

    Hello all,

    I have an .Net Core API and UI application. I imported a library in my API that I need to make calls to a service for. I now see that I need to open a websocket connection to get continous data as well. This is where I become confused. I want the UI to get constant changes from the websockets.

    Do I open my websocket connection on my UI? I import that library to my .net core ui project so I can get continuous data and when a condition hits I use httpclient to call the API?

    Or do I do it all on my API but if so im not positive how to update my UI with the constantly changing price.

    Thank you

    Wednesday, May 5, 2021 3:29 PM

All replies

  • User-474980206 posted

    WebSocket is protocol like http. it allows two way communication on the same tcp/ip connection, rather than requiring two connection like http. It was designed for browser to server 2 way communication as there was already server to server protocols.

    if you want the browser client to get updates from the server, the client can poll or use web sockets. Signal/R is a WebSocket library for asp.net core. As WebSocket is a persistent connection, mvc controllers don't make sense.  Signal/R uses a hub and message protocol. Your asp.net core app will handle webpage and Ajax request. the Signal/R hub will be used by the client to get updates. you will write a server worker routine to get the data and update the hub.

      https://docs.microsoft.com/en-us/aspnet/core/signalr/introduction?view=aspnetcore-5.0

    note: polling still may make more sense unless realtime deliver (less than a couple seconds) is a requirement. 

    Wednesday, May 5, 2021 3:51 PM
  • User-544325736 posted

    Thank you Bruce,

    Ok! So I got my websockets to capture and stop capturing data!.

    Now here is my new main question.
    I currently have an API.
    This is where my websocket starts and stops as well as where I execute my trades.
    I understand how to make my UI execute my trades by using httpclient and json to send data back and forth.
    How would I do this with my WebSocket?
    How would I send the Data incoming to my API to my UI?
    Data continously comes in on the API (from the websockets) How can I send that to my front end?
    Here is my API method.

    [HttpGet("StartBTCCapture")]
            public async Task<IActionResult> StartBTCCapture()
            {
                if (_binanceSocketClient != null)
                {
                    _logger.LogInformation("Capture Starting...");
                    _marketFeed.StartBTCCapture();
                    //var incomingBTC = _binanceSocketClient.SubscribeToTradeUpdatesAsync("BTCUSD", async (data) =>
                    //{
                    //    //(data);
                    //    _logger.LogInformation(data.Price.ToString());
                    //});
                    return Ok();
                }
                return BadRequest();
            }
    
    
     public async Task StartBTCCapture()
            {
                try
                {
                    if (_binanceSocketClient != null)
                    {
                        var incomingBTC = await _binanceSocketClient.SubscribeToTradeUpdatesAsync("BTCUSD", async (data) =>
                        {
                            //(data);
                            // _logger.LogInformation(data.Price.ToString());
                            Console.WriteLine(data.Price);
                        });
                    }
                }
                catch(Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }

    Thursday, May 6, 2021 4:01 PM
  • User-474980206 posted

    Depends on what reliability you need, in general a UI client would open its own web socket to the UI server. Then when trade data is received, it would call the UI server to send the data to its client.

    in practice you generally implement queues and logs depending on the reliability requirements. If a client loses connection how does it catch up? What if the trade sockets loses connection?

    Thursday, May 6, 2021 7:14 PM
  • User-544325736 posted

    I understand about that client loses connection and the catch up. As of for now I am only streaming the current market price. So if the client leaves and comes back they just need the new current price.

    On my API I have successful websocket data streaming to my information console.

    On my UI I would like to get that data. I implemented websockets on my ui a few different ways by researching but no luck yet. I tried using an HttpListener to possible just grab my API data or using the websockets without SignalR service.

    Here is what I have do you have any idea where I went wrong? Or am I completely doing it wrong? I appreciate all info you give me.

    UI

     public void ConfigureServices(IServiceCollection services)
            {
     // WebSockets Connection
                var webSocketOptions = new WebSocketOptions()
                {
                    KeepAliveInterval = TimeSpan.FromSeconds(120),
                };
                app.UseWebSockets(webSocketOptions);
                app.Use(async (context, next) =>
                {
                    if (context.Request.Path == "/ws")
                    {
                        if (context.WebSockets.IsWebSocketRequest)
                        {
                            WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                            await Echo(context, webSocket);
                        }
                        else
                        {
                            context.Response.StatusCode = 400;
                        }
                    }
                    else
                    {
                        await next();
                    }
                });
                async Task Echo(HttpContext context, WebSocket webSocket)
                {
                    var buffer = new byte[1024 * 4];
                    WebSocketReceiveResult result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer),
                        CancellationToken.None);
    
                    while (!result.CloseStatus.HasValue)
                    {
                        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType,
                        result.EndOfMessage, CancellationToken.None);
                        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                        Console.WriteLine(result);
                    }
                    await webSocket.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription,
                    CancellationToken.None);
                }
    }
    
    Controller
     public async Task<IActionResult> Index()
            {
                //var conn = new WebSocket();
    
                HttpListener httpListener = new HttpListener();
                httpListener.Prefixes.Add("ws://localhost:50021/StartBTCCapture");
                httpListener.Start();
                var buffer = new byte[1024 * 4];
    
                HttpListenerContext context = await httpListener.GetContextAsync();
                if (context.Request.IsWebSocketRequest)
                {
                    HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null);
                    WebSocket webSocket = webSocketContext.WebSocket;
                    while (webSocket.State == WebSocketState.Open)
                    {
                        await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                    }
                }
    
                return View();
            }

    I want sure how to use the 'echo' in my controller view method

    Thursday, May 6, 2021 8:27 PM
  • User-474980206 posted

    you need to create a communication pipeline between the echo routine and the index.  each index request will register with echo. 

    echo:

     

     while (!result.CloseStatus.HasValue)
                    {
                        await webSocket.SendAsync(new ArraySegment<byte>(buffer, 0, result.Count), result.MessageType,
                        result.EndOfMessage, CancellationToken.None);
                        result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                        Console.WriteLine(result);
                        // some thread safe pipeline 
                        RegisteredClients.Send(result);
                    }

    in index:

                   WebSocket webSocket = webSocketContext.WebSocket;
                   var me = Guid.NewGuid();
                   RegisteredClients.Add(me);
                    while (webSocket.State == WebSocketState.Open)
                    {
                         var result = await RegisteClients.GetMessage(me);
                        await webSocket.SendAsync(result, CancellationToken.None);
                    }
                   RegisteredClients.Remove(me);
    

    hint: you should use a concurrent collection of semaphores to implement the pipeline. I'd probably uses queues for each registered client

    Monday, May 10, 2021 3:45 PM