es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Manejo de la clase close y dispose de WebSocket (Observable.Using)

¿Cómo manejo el cierre y la eliminación de WebSocket? También es necesario eliminar simple.SubscribeToTicker().Subscribe(...).

Vi a algunas personas haciéndolo de la siguiente manera, pero no estoy seguro de cómo se comporta Observable.Using(...) y cuándo realiza la eliminación.

cs
var message =
Observable.Using(() => ws,
_ => Observable.FromEventPattern(h => ws.MessageReceived += h,
h => ws.MessageReceived -= h));

Fragmento de código

using System.Net;
using System.Reactive.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using RestSharp;
using WebSocket4Net;

namespace SimpleTest;

public class Simple
{
    public RestPriceTicker24Hr? GetTicker()
    {
        const string uri = "https://api.binance.com";

<pre><code>    var client = new RestClient(uri);
    var request = new RestRequest("/api/v3/ticker/24hr?symbol=BNBUSDT", Method.GET);
    var response = client.Execute(request);

    if (response.StatusCode != HttpStatusCode.OK)
        throw new InvalidOperationException();

    var content = response.Content;

    var deserialize = JsonSerializer.Deserialize<RestPriceTicker24Hr>(content, new JsonSerializerOptions
    {
        NumberHandling = JsonNumberHandling.AllowReadingFromString
    });

    return deserialize;
}

public IObservable<PriceTicker24Hr?> SubscribeToTicker()
{
    const string uri = "wss://stream.binance.com:9443/ws";

    var ws = new WebSocket($"{uri}/bnbusdt@ticker") // TODO: Dispose
    {
        AutoSendPingInterval = 3, // 3 segundos
        EnableAutoSendPing = true
    };

    ws.Open();

    ws.Error += (_, e) => { Console.WriteLine($"Exception: {e.Exception.Message}"); };

    ws.Opened += (_, _) => { Console.WriteLine("Conexión abierta"); };

    ws.Closed += (_, _) => { Console.WriteLine("Conexión cerrada"); };

    //var message =
    //    Observable.Using(() => ws,
    //        _ => Observable.FromEventPattern<MessageReceivedEventArgs>(h => ws.MessageReceived += h,
    //            h => ws.MessageReceived -= h));

    var message =
        Observable.FromEventPattern<MessageReceivedEventArgs>(h => ws.MessageReceived += h,
            h => ws.MessageReceived -= h);

    return message.Select(e =>
        JsonSerializer.Deserialize<PriceTicker24Hr>(e.EventArgs.Message, new JsonSerializerOptions
        {
            NumberHandling = JsonNumberHandling.AllowReadingFromString
        }));
}
</code></pre>

}

public class Program
{
    private static void GetData()
    {
        var simple = new Simple();

<pre><code>    var ticker = simple.GetTicker();
    simple.SubscribeToTicker().Subscribe(message => { Console.WriteLine($"Mensaje: {message?.BestAskPrice}"); }); // TODO: Dispose
}

private static void Main()
{
    GetData();

    Console.ReadKey();
}
</code></pre>

}

public class PriceTicker24Hr
{
    [JsonPropertyName("e")] public string? EventType { get; set; }

<pre><code>[JsonPropertyName("E")] public long EventTime { get; set; }

[JsonPropertyName("s")] public string? Symbol { get; set; }

[JsonPropertyName("p")] public decimal PriceChange { get; set; }

[JsonPropertyName("P")] public decimal PriceChangePercent { get; set; }

[JsonPropertyName("w")] public decimal WeightedAveragePrice { get; set; }

[JsonPropertyName("x")] public decimal PreviousClosePrice { get; set; }

[JsonPropertyName("c")] public decimal LastPrice { get; set; }

[JsonPropertyName("Q")] public decimal LastQuantity { get; set; }

[JsonPropertyName("b")] public decimal BestBidPrice { get; set; }

[JsonPropertyName("B")] public decimal BestBidQuantity { get; set; }

[JsonPropertyName("a")] public decimal BestAskPrice { get; set; }

[JsonPropertyName("A")] public decimal BestAskQuantity { get; set; }

[JsonPropertyName("o")] public decimal OpenPrice { get; set; }

[JsonPropertyName("h")] public decimal HighPrice { get; set; }

[JsonPropertyName("l")] public decimal LowPrice { get; set; }

[JsonPropertyName("v")] public decimal TotalTradedBaseVolume { get; set; }

[JsonPropertyName("q")] public decimal TotalTradedQuoteVolume { get; set; }

[JsonPropertyName("O")] public long OpenTime { get; set; }

[JsonPropertyName("C")] public long CloseTime { get; set; }

[JsonPropertyName("F")] public long FirstTradeId { get; set; }

[JsonPropertyName("L")] public long LastTradeId { get; set; }

[JsonPropertyName("n")] public long Count { get; set; }
</code></pre>

}

public class RestPriceTicker24Hr
{
    [JsonPropertyName("symbol")] public string? Symbol { get; set; }
    [JsonPropertyName("priceChange")] public decimal PriceChange { get; set; }

<pre><code>[JsonPropertyName("priceChangePercent")]
public decimal PriceChangePercent { get; set; }

[JsonPropertyName("weightedAvgPrice")] public decimal WeightedAveragePrice { get; set; }
[JsonPropertyName("prevClosePrice")] public decimal PreviousClosePrice { get; set; }
[JsonPropertyName("lastPrice")] public decimal LastPrice { get; set; }
[JsonPropertyName("lastQty")] public decimal LastQuantity { get; set; }
[JsonPropertyName("bidPrice")] public decimal BestBidPrice { get; set; }
[JsonPropertyName("bidQty")] public decimal BestBidQuantity { get; set; }
[JsonPropertyName("askPrice")] public decimal BestAskPrice { get; set; }
[JsonPropertyName("askQty")] public decimal BestAskQuantity { get; set; }
[JsonPropertyName("openPrice")] public decimal OpenPrice { get; set; }
[JsonPropertyName("highPrice")] public decimal HighPrice { get; set; }
[JsonPropertyName("lowPrice")] public decimal LowPrice { get; set; }
[JsonPropertyName("volume")] public decimal TotalTradedBaseVolume { get; set; }
[JsonPropertyName("quoteVolume")] public decimal TotalTradedQuoteVolume { get; set; }
[JsonPropertyName("openTime")] public long OpenTime { get; set; }
[JsonPropertyName("closeTime")] public long CloseTime { get; set; }
[JsonPropertyName("firstId")] public long FirstTradeId { get; set; }
[JsonPropertyName("lastId")] public long LastTradeId { get; set; }
[JsonPropertyName("count")] public long Count { get; set; }
</code></pre>

}
Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para manejar el cierre y la eliminación de WebSocket en C#, puedes utilizar el método Observable.Using. Este método crea una secuencia observable y se asegura de que el recurso desechable se elimine correctamente cuando se finaliza la secuencia o se cancela su suscripción.

    En el fragmento de código proporcionado, puedes modificar el método SubscribeToTicker para que utilice Observable.Using y desechar la instancia de WebSocket cuando ya no se necesite:

    public IObservable<priceticker24hr?> SubscribeToTicker()
    {
        const string uri = "wss://stream.binance.com:9443/ws";
    
        return Observable.Using(
            () => new WebSocket($"{uri}/bnbusdt@ticker") 
            {
                AutoSendPingInterval = 3,
                EnableAutoSendPing = true
            },
            ws =>
            {
                ws.Open();
                ws.Error += (_, e) => { Console.WriteLine($"Exception: {e.Exception.Message}"); };
                ws.Opened += (_, _) => { Console.WriteLine("Connection opened"); };
                ws.Closed += (_, _) => { Console.WriteLine("Connection closed"); };
    
                var message = Observable.FromEventPattern<messagereceivedeventargs>(
                    h => ws.MessageReceived += h,
                    h => ws.MessageReceived -= h);
    
                return message.Select(e =>
                    JsonSerializer.Deserialize<priceticker24hr>(e.EventArgs.Message, new JsonSerializerOptions
                    {
                        NumberHandling = JsonNumberHandling.AllowReadingFromString
                    }));
            });
    }
    

    Con este cambio, la instancia de WebSocket se desechará automáticamente cuando se finalice la secuencia observable creada por SubscribeToTicker. Esto asegura que los recursos se limpien correctamente y evita posibles fugas de memoria.

    Además, si necesitas desechar la suscripción devuelta por SubscribeToTicker().Subscribe(...), puedes simplemente llamar a .Dispose() cuando hayas terminado con ella.</priceticker24hr?>

Comments are closed.