Been using C# Websocket client in my app using System.Net.WebSockets. All my code to send and receive is working well, however I can not for the life of me successfully disconnect (Which i need to do so i can then use the client again w/ different hostname). I have created a quick demo to show my problem.
This is my Program code:
class Program
{
static void Main(string[] args)
{
GetDocList();
Console.ReadLine();
}
static async Task<string> GetDocList()
{
var client = new myWSClient(new Uri("ws://localhost:9999/qlcplusWS"));
var docs = await client.ConnectAndDisconnect();
return docs;
}
}
This is my Class that I am using
public class myWSClient
{
private ClientWebSocket _client;
public Uri _myURI;
public myWSClient(Uri MyURI)
{
_client = new ClientWebSocket();
_myURI = MyURI;
}
public async Task<string> ConnectAndDisconnect()
{
string dummyreturn = "";
await _client.ConnectAsync(_myURI, CancellationToken.None);
Console.WriteLine("Connected");
string status = "";
Console.WriteLine("Waiting to Disconnect, but it will never happen :(");
await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, status, CancellationToken.None);
Console.WriteLine("Disconnected mate");
return dummyreturn;
}
}
Am I using the wrong method or is my code just syntactically wrong?
You have to wait for the methods to return as those are asynchronous and the main function is going to continue executing after starting the task of the GetDocList() method.
GetDocList().Wait();
Related
I am writing a program to interact with the Spotify API via a command line.
I have some code here to take a command, and then execute the relevant function to retrieve data from Spotify.
This code shows the problem, I have left out irrelevant code.
public class CommandHandler
{
public async void HandleCommands()
{
var spotifyCommand = GetCommand();
if (spotifyCommand == SpotifyCommand.Current)
{
WriteCurrentSong(await new PlayerController().GetCurrentlyPlayingAsync());
}
if (spotifyCommand == SpotifyCommand.NextTrack)
{
WriteCurrentSong(await new PlayerController().NextTrackAsync());
}
Console.ReadLine();
//end of program
}
}
public class PlayerController
{
public async Task<SpotifyCurrentlyPlaying> NextTrackAsync()
{
using (var httpClient = new HttpClient())
{
//removed code to set headers etc
//Skip Track
var response = await httpClient.PostAsync("https://api.spotify.com/v1/me/player/next", null);
if (response.StatusCode != HttpStatusCode.NoContent)
{
//code to handle this case, not important
}
return await GetCurrentlyPlayingAsync();
}
}
public async Task<SpotifyCurrentlyPlaying> GetCurrentlyPlayingAsync()
{
using (var httpClient = new HttpClient())
{
//removed code to set headers etc
var response = await httpClient.GetAsync("https://api.spotify.com/v1/me/player/currently-playing");
response.EnsureSuccessStatusCode();
return JsonSerializer.Deserialize<SpotifyCurrentlyPlaying>(await response.Content.ReadAsStringAsync());
}
}
}
The two if statements in HandleCommands() call into PlayerController and await the result of the method. For some reason if I use await PlayerController.MethodCall() the call is made, however, the result does not return before the program finishes executing.
Strangely, this is not an issue if I use PlayerController.MethodCall().Result.
Any help will be greatly appreciated, as I would really rather not use .Result. Thanks!
Signature of the HandleCommands is an issue
public async void HandleCommands()
{
// ...
}
You are not showing how this method is called, but I assume it is something like below:
var handler = new CommandHandler();
handler.HandleCommands();
Because of async void method doesn't return Task and caller can not "observe" it's completion.
So application finishes without waiting for task to complete.
To fix - change method signature to below and await for task to complete
public async Task HandleCommands()
{
// ...
}
var handler = new CommandHandler();
await handler.HandleCommands();
Sorry, if this is a stupid question but I don't find any useful information in the internet.
Has anyone ever tried to implement the observer pattern in C# using gRPC as communication?
If yes, please show me the link.
Many thanks in advance and best regards.
I have implemented a client convenience class wrapper to turn server streaming calls into regular events for a project I am working. Not sure if this is what you are after. Here is a simple gRPC server that just publishes the time as a string once every second.
syntax = "proto3";
package SimpleTime;
service SimpleTimeService
{
rpc MonitorTime(EmptyRequest) returns (stream TimeResponse);
}
message EmptyRequest{}
message TimeResponse
{
string time = 1;
}
The server implementation, which just loops once a second returning the string representation of the current time until canceled, is as follows
public override async Task MonitorTime(EmptyRequest request, IServerStreamWriter<TimeResponse> responseStream, ServerCallContext context)
{
try
{
while (!context.CancellationToken.IsCancellationRequested)
{
var response = new TimeResponse
{
Time = DateTime.Now.ToString()
};
await responseStream.WriteAsync(response);
await Task.Delay(1000);
}
}
catch (Exception)
{
Console.WriteLine("Exception on Server");
}
}
For the client, I created a class that contains the gRPC client and exposes the results of the server streaming MonitorTime call as a plain ole .net event.
public class SimpleTimeEventClient
{
private SimpleTime.SimpleTimeService.SimpleTimeServiceClient mClient = null;
private CancellationTokenSource mCancellationTokenSource = null;
private Task mMonitorTask = null;
public event EventHandler<string> OnTimeReceived;
public SimpleTimeEventClient()
{
Channel channel = new Channel("127.0.0.1:50051", ChannelCredentials.Insecure);
mClient = new SimpleTime.SimpleTimeService.SimpleTimeServiceClient(channel);
}
public void Startup()
{
mCancellationTokenSource = new CancellationTokenSource();
mMonitorTask = Task.Run(() => MonitorTimeServer(mCancellationTokenSource.Token));
}
public void Shutdown()
{
mCancellationTokenSource.Cancel();
mMonitorTask.Wait(10000);
}
private async Task MonitorTimeServer(CancellationToken token)
{
try
{
using (var call = mClient.MonitorTime(new SimpleTime.EmptyRequest()))
{
while(await call.ResponseStream.MoveNext(token))
{
var timeResult = call.ResponseStream.Current;
OnTimeReceived?.Invoke(this, timeResult.Time);
}
}
}
catch(Exception e)
{
Console.WriteLine($"Exception encountered in MonitorTimeServer:{e.Message}");
}
}
}
Now create the client and subscribe to the event.
static void Main(string[] args)
{
SimpleTimeEventClient client = new SimpleTimeEventClient();
client.OnTimeReceived += OnTimeReceivedEventHandler;
client.Startup();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
client.Shutdown();
}
private static void OnTimeReceivedEventHandler(object sender, string e)
{
Console.WriteLine($"Time: {e}");
}
Which when run produces
I have left out a lot of error checking and such to make the example smaller. One thing I have done is for gRPC interfaces with many server streaming calls that may or may not be of interest to call clients, is to implement the event accessor (add,remove) to only call the server side streaming method if there is a client that has subscribed to the wrapped event. Hope this is helpful
I have implemented a soap client using a Async method. I want this method to return a string value that I get from the API server to my main Thread or to another method (whichever method is calling). How do I do this:
MAIN THREAD
static void Main(string[] args)
{
TEXT().GetAwaiter().OnCompleted(() => { Console.WriteLine("finished"); });
Console.ReadKey();
// if I do it like this
// var test = TEXT().GetAwaiter().OnCompleted(() => { Console.WriteLine("finished"); });
// it gives me error: Cannot assign void to an implicitly-typed local variable
}
ASYNC METHOD
public static async Task<string> TEXT()
{
Uri uri = new Uri("http://myaddress");
HttpClient hc = new HttpClient();
hc.DefaultRequestHeaders.Add("SOAPAction", "Some Action");
var xmlStr = "SoapContent"; //not displayed here for simplicity
var content = new StringContent(xmlStr, Encoding.UTF8, "text/xml");
using (HttpResponseMessage response = await hc.PostAsync(uri, content))
{
var soapResponse = await response.Content.ReadAsStringAsync();
string value = await response.Content.ReadAsStringAsync();
return value; //how do I get this back to the main thread or any other method
}
}
In a pre-C# 7.0 console application it can be achieved as simple as this:
public static void Main()
{
string result = TEXT().Result;
Console.WriteLine(result);
}
In this case TEXT can be considered a usual method, which returns Task<string>, so its result is available in Result property. You don't need to mess with awaiter, results etc.
At the same time, you cannot do this in most types of applications (WinForms, WPF, ASP.NET etc.) and in this case you will have to use async/await across all your application:
public async Task SomeMethod()
{
string result = await TEXT();
// ... do something with result
}
If you plan to do a lot of async in a console application, I recommend using this sort of MainAsync pattern:
static public void Main(string[] args) //Entry point
{
MainAsync(args).GetAwaiter().GetResult();
}
static public Task MainAsync(string[] args) //Async entry point
{
await TEXT();
Console.WriteLine("finished");
}
If you upgrade to C# 7.1 or later, you can then remove the Main method and use async main.
Or if you ever migrate this code to an ASP.NET or WinForms application, you can ignore Main and migrate the code in MainAsync (otherwise you will run afoul of the synchronization model and get deadlocked).
In C# 7.0+, you can use async Task Main
static async Task Main(string[] args)
{
var result = TEXT().ConfigureAwait(false)
Console.ReadKey();
}
for older versions of C#
public static void Main(string[] args)
{
try
{
TEST().GetAwaiter().GetResult();
}
catch (Exception ex)
{
WriteLine($"There was an exception: {ex.ToString()}");
}
}
i tried this code which i've copied from the github page of discord.net this one works perfectly fine:
using Discord;
using Discord.WebSocket;
using System;
using System.Threading.Tasks;
namespace Adivisor
{
public class Program
{
private DiscordSocketClient _client;
public static void Main(string[] args) => new Program().MainAsync().GetAwaiter().GetResult();
public async Task MainAsync()
{
_client = new DiscordSocketClient();
_client.Log += Log;
_client.MessageReceived += MessageReceived;
string token = ":P";
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();
await Task.Delay(-1);
}
private async Task MessageReceived(SocketMessage message)
{
if (message.Content == "!hi")
{
await message.Channel.SendMessageAsync("Hello!");
}
}
private Task Log(LogMessage msg)
{
Console.WriteLine(msg.ToString());
return Task.CompletedTask;
}
}
}
after i made a little editing on MessageReceived now it looks like this:
private async Task MessageReceived(SocketMessage message)
{
await message.Channel.SendMessageAsync("Hello!");
}
pratically i just removed the if, but there is a huge differnce, seems like the without the if MessageReceived gets called forever...
Like what Xiaoy312 stated, whenever your bot send a message, it also receives it's own message.
(The same also applies for your own user account! Try doing an #everyone ping in chat and you will see it being highlighted even though it was you who sent it.)
You can make your bot ignore it other bots messages by doing this:
//Ignores all bots messages
//Where message is your received SocketMessage
if (message.Author.IsBot) { return; }
Or you can make it check if the message's author's ID equals to the bot's ID. You can check the documentation here.
I have modified the Xamarin/Azure TODO example. But the code is stuck in
IMobileServiceTable.ToListAsync()
This is my IO class:
class DataIO
{
BackgroundWorker DatabaseWorker = new BackgroundWorker();
IMobileServiceTable<UserPosition> PositionTable;
MobileServiceClient client;
public DataIO()
{
Init();
}
public void Init()
{
client = new MobileServiceClient(Constants.ApplicationURL);
PositionTable = client.GetTable<UserPosition>();
}
async void AddEntry(UserPosition entry)
{
await PositionTable.InsertAsync(entry);
}
public async Task<List<UserPosition>> GetEntries()
{
List<UserPosition> Entries = await PositionTable.ToListAsync();
return Entries;
}
public async void DeleteEntry(UserPosition entry)
{
await PositionTable.DeleteAsync(entry);
}
public async void AddToDatabase(UserPosition item)
{
await PositionTable.InsertAsync(item);
}
}
The debugger dosen't neither step over it nor throws an error.
How to handle that?
In an earlier call, there wasn't any problem.
EDIT:
I've rewritten the GetEntries() method to:
public async Task<List<UserPosition>> GetEntries()
{
Task<List<UserPosition>> task = PositionTable.ToListAsync();
List<UserPosition> entries = await task;
return entries;
}
according to this example. But the debugger just stays in the line
Task<List<UserPosition>> task = PositionTable.ToListAsync();
AFAIK, IMobileServiceTable.ToListAsync() would send the request as follows for retrieving the result:
Get https://<your-app-name>.azurewebsites.net/tables/UserPosition
I would recommend you using Fiddler to collect the network traces when calling IMobileServiceTable.ToListAsync(). Also, you could access the table endpoint from your mobile app via the browser to make sure your mobile app could work as expected. Additionally, here is a great tutorial about Handling Data in Mobile Clients, you could refer to it.