I'm trying to figure out a way to create a generic Websocket JsonRpc client.
After connecting I'm starting a loop to listen for data coming from the WebSocket API and sending that data to the event as a string. I'd like to return a generic JsonRpcResponse<T>
object instead but not sure how or if it's possible.
Where JsonRpcResponse
has an Id
and Method
fields as defined in the spec and T
is a specific type depending on the data received.
From what I've seen there's no way to use generics here since I'd have to call another event with a non-generic type or object
to pass that data along.
public event Func<string, Task>? OnDataReceived;
public async Task ConnectAsync()
{
Uri uri = new Uri(_url);
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(3000);
await _client.ConnectAsync(uri, cancellationTokenSource.Token);
// Start listening for data
await Task.Factory.StartNew(async () =>
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
while (_client.State == WebSocketState.Open && !cancellationTokenSource.IsCancellationRequested)
{
var receivedData = await ReadStringAsync(cancellationTokenSource.Token);
if (OnDataReceived != null)
{
await OnDataReceived.Invoke(receivedData);
}
}
};
}
How about this:
namespace GenericJsonResponse {
/// <summary>
/// Desired returned type
/// </summary>
/// <typeparam name="T"></typeparam>
public class JsonResponse<T> {
public T? Data { get; set; }
public int Id { get; set; } = 0;
public string Method { get; set; } = string.Empty;
/// <summary>
/// Convert string to anew instance
/// </summary>
/// <param name="json"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
/// <remarks>will have to add to each sub class</remarks>
public static T FromJson(string json) {
throw new NotImplementedException();
}
}
/// <summary>
/// Generic socket listener / sub class per type
/// </summary>
/// <typeparam name="T"></typeparam>
public class GenericSocketListener<T> {
/// <summary>
/// exposes event with generic response
/// </summary>
public event Func<string, Task<JsonResponse<T>>>? OnDataReceived;
/// <summary>
/// Listen to socket
/// </summary>
/// <param name="token"></param>
/// <returns></returns>
public virtual async Task Listen( CancellationToken token) {
string data = string.Empty;
while (! token.IsCancellationRequested) {
// listen... and get typed result, save string to data
JsonResponse<T> result = await OnDataReceived.Invoke(data);
}
}
}
/// <summary>
/// Dummy poco
/// </summary>
public class Person {
public string FirstName { get; set; } = string.Empty;
public string LastName { get; set; } = string.Empty;
}
/// <summary>
/// Class that will listen to people
/// </summary>
public class PersonSocketListener : GenericSocketListener<Person> {
}
}