Implementing RunAsync() correctly - c#

I'm working on a code that regularly screenshots a web page for an image, scans the pixel colors of the image, and if a color is found, connects asynchronously to a web API.
I have worked out how to do the color scanning and the connection separately and now I have to join the two logics but I'm not sure of the best way to do it .
The scanning web page/image scan code is essentially this:
static void Main(string[] args)
{
while (true)
{
try
{
System.Threading.Thread.Sleep(5000); //refresh speed
string color = ReadColor(driver, webElement);
if (color== "blue")
{
//should connect for blue case and run the Blue() function below
}
if (color== "green")
{
//should connect for green case
}
}
catch
{
}
}
}
the HttpClient connection goes like this:
static HttpClient client = new HttpClient();
static void Main()
{
RunAsync().Wait();
}
static async Task RunAsync()
{
client.BaseAddress = new Uri("website");
Data data = new Data { };
try
{
data = await Green();
data = await blue(); //functions to run depending on color
}
catch (Exception e)
{
}
}
how should the RunAsync().Wait(); method be properly inserted in the first example and how should I call the correct function?
EDIT:
ok so eventually I'm doing it this way:
static void Main(string[] args)
{
while (true)
{
try
{
System.Threading.Thread.Sleep(1000);
string signal = ReadGraph(driver, webElement); //////READ CHART
if (signal == "blue")
{
Task.Run(async () => await RunAsync(signal)).Wait();
}
if (signal == "green")
{
RunAsync(signal);
}
}
catch
{
}
}
}
however, whenever the RunAsync is called, it executes but the thread never returns to the main loop.
I tried
Task.Run(async () => await RunAsync(signal)).Wait()
Task.Run(async () => await RunAsync(signal)).Wait()
RunAsync(signal);
RunAsync(signal).wait();
with the same result, what am I doing wrong?

This is how you should do it if you want async:
static async void Main(string[] args)
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(1.0));
string signal = ReadGraph(driver, webElement);
if (signal == "blue")
{
await RunAsync(signal);
}
if (signal == "green")
{
await RunAsync(signal);
}
}
}

Related

await Task.Delay(1000); causing crashes - Unity C#

Main Issue:
Unsure of what's happening in the background, but apparently whenever the line await Task.Delay(1000); is called Unity would turn unresponsive/freezes up.
Error msg:
Tried checking callbacks from unity's profiler, but whenever the line in question were triggered unity would instantly turn unresponsive and not allowing any interaction (no callbacks/error messages were given out either).
Goal:
The goal here is to simply call tryActivities[0] then, await for 1 second and then return true, and prints "Fished successfully!", without any crashing.
Suspicions:
A suspicion I have is that the line tryActivities.Add(new Func<bool>(() => fs(currentSlot.basicData.typeID).Result)); need some sort of await? Though I'm also unsure of how to implement that either.
Inventory inventory; (Inventory.cs)
List<Func<bool>> tryActivities = new List<Func<bool>>();
public delegate Task<bool> Fish(int ID); Fish fs;
void Start()
{
fs = new Fish(activities.Fish);
tryActivities.Add(new Func<bool>(() => fs(currentSlot.basicData.typeID).Result));//await? how?
}
public void Interact()//called when a button is pressed
{
if (TryPlaceOrUse()) print("Fished successfully!");
else print("Fishing failed");
}
bool TryPlaceOrUse()
{
if (tryActivities[(int)currentSlot.basicData.myActivity]())//tryActivities[0]
return true;
return false;
}
Activities activities; (Activities.cs)
public async Task<bool> Fish(int ID)
{
await Task.Delay(1000);//crashes here
return true;
}
This might do what you want. This is how you'd use a list of async Funcs, which is really just a list of Funcs that return Tasks of bool.
public class Program
{
public delegate Task<bool> Fish(int ID);
Fish fs;
List<Func<Task<bool>>> tryActivities = new List<Func<Task<bool>>>();
public async static Task Main()
{
Console.WriteLine("Hello, World!");
Program program = new Program();
program.Start();
await program.Interact();
}
void Start()
{
fs = new Fish(Activities.Fish);
tryActivities.Add(new Func<Task<bool>>(async () => await fs(4)));//await? how? like this :)
}
public async Task Interact() //called when a button is pressed
{
if (await TryPlaceOrUse())
Console.WriteLine("Fished successfully!");
else
Console.WriteLine("Fishing failed");
}
async Task<bool> TryPlaceOrUse()
{
if (await tryActivities[0]()) //tryActivities[0]
return true;
return false;
}
}
public class Activities
{
public static async Task<bool> Fish(int ID)
{
await Task.Delay(1000);//does not crash here
return true;
}
}

BrowserFetcher exit application using await

I'm using Puppeteer-Sharp to download the html of a site, I created a method called GetHtml which return a string that contains the site content. The problem is that when I call the line await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
The application exit without any errors, this is my code:
public class Program
{
public static void Main(string[] args)
{
try
{
new FixtureController().AddUpdateFixtures();
}
catch (Exception ex)
{
new Logger().Error(ex);
}
}
}
public async Task AddFixtures()
{
int monthDays = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month);
var days = Enumerable.Range(1, monthDays).Select(x => x.ToString("D2")).ToArray();
HtmlDocument doc = new HtmlDocument(); //this is part of Htmlagilitypack library
foreach (var day in days)
{
//Generate url for this iteration
Uri url = new Uri("somesite/" + day);
var html = await NetworkHelper.GetHtml(url);
doc.LoadHtml(html);
}
}
so each foreach iteration will generate an url which download the data, and the method GetHtml should return the html but the application exit (without errors) when reach var html = .., this is the code of GetHtml:
public static async Task<string> GetHtml(Uri url)
{
try
{
//here the crash
await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
}
catch (Exception e)
{
//No breakpoint point firing
}
await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
using (Page page = await browser.NewPageAsync())
{
await page.GoToAsync(url.ToString());
return await page.GetContentAsync();
}
}
Your main method does not wait for the result of your async call. The main method exits, closing the application. To fix it you need to wait for the async method to finish.
If you're using C# 7.1 or newer you can use async Main:
public class Program
{
public static async void Main()
{
await TestAsync();
}
private static async Task TestAsync()
{
await Task.Delay(5000);
}
}
Otherwise you need to wait synchronously:
public class Program
{
public static void Main()
{
TestAsync().GetAwaiter().GetResult();
}
private static async Task TestAsync()
{
await Task.Delay(5000);
}
}

C# Pausing Async Task works in one method, but not another

I have a class called PauseOrCancelToken, created by another class, PauseOrCancelTokenSource. PauseOrCancelToken basically encapsulates both a CancellationToken and PauseToken implemented from this MSDN blog post: https://blogs.msdn.microsoft.com/pfxteam/2013/01/13/cooperatively-pausing-async-methods/
I have tested it, and in a simple example use case (MethodA in the code I am about to post), it works as intended.
However, when I test it with non-trivial code that I intend to use in production (MethodB/ProxyTester.Start()), it is not pausing the async task.
public partial class PauseCancelForm : Form
{
private PauseOrCancelTokenSource pcts = new PauseOrCancelTokenSource();
public PauseCancelForm()
{
InitializeComponent();
}
private void StartButton_Click(object sender, EventArgs e)
{
Task.Run(() =>
{
MethodA(pcts.Token).Wait();
});
}
private async Task MethodA(PauseOrCancelToken pct)
{
//Pauses as intended when the pause button is clicked.
for (int i = 0; i < 10000; i++)
{
Console.WriteLine(i);
await Task.Delay(1000);
await pct.PauseOrCancelIfRequested();
}
}
private async Task MethodB(PauseOrCancelToken pct)
{
//Doesn't pause.
var proxies = new List<Proxy>();
var judges = new List<ProxyJudge>();
for (int i = 0; i < 10000; i++)
{
proxies.Add(new Proxy("127.0.0." + RandomUtility.GetRandomInt(1, 100), 8888));
}
judges.Add(new ProxyJudge("http://azenv.net"));
await ProxyTester.Start(proxies, judges, pct);
}
private void PauseButton_Click(object sender, EventArgs e)
{
pcts.Pause();
}
private void StopButton_Click(object sender, EventArgs e)
{
pcts.Cancel();
}
private void ResumeButton_Click(object sender, EventArgs e)
{
pcts.Resume();
}
}
public class PauseOrCancelTokenSource
{
private PauseTokenSource pts = new PauseTokenSource();
private CancellationTokenSource cts = new CancellationTokenSource();
public PauseOrCancelToken Token { get { return new PauseOrCancelToken(pts, cts); } }
public void Pause()
{
pts.IsPaused = true;
}
public void Resume()
{
pts.IsPaused = false;
}
public void Cancel()
{
cts.Cancel();
}
}
public class PauseOrCancelToken
{
private PauseToken pt;
private CancellationToken ct;
public PauseOrCancelToken(PauseTokenSource pts, CancellationTokenSource cts)
{
this.pt = pts.Token;
this.ct = cts.Token;
}
public async Task PauseIfRequested()
{
await pt.WaitWhilePausedAsync();
}
public void CancelIfRequested()
{
ct.ThrowIfCancellationRequested();
}
public async Task PauseOrCancelIfRequested()
{
await PauseIfRequested();
CancelIfRequested();
}
}
public class ProxyTester
{
public async static Task Start(List<Proxy> proxies, List<ProxyJudge> judges, PauseOrCancelToken pct, List<ProxyTest> tests = null)
{
if (tests == null)
{
tests = new List<ProxyTest>();
}
//Get external IP to check if proxy is anonymous.
var publicIp = await WebUtility.GetPublicIP();
//Validate proxy judges.
var tasks = new List<Task>();
foreach (var judge in judges)
{
tasks.Add(Task.Run(async () => {
judge.IsValid = await judge.TestValidityAsync();
await pct.PauseOrCancelIfRequested();
}));
}
await Task.WhenAll(tasks);
var validJudges = from judge in judges
where judge.IsValid
select judge;
if (validJudges.Count() == 0)
{
throw new Exception("No valid judges loaded.");
}
//Validate proxy tests.
tasks.Clear();
foreach (var test in tests)
{
tasks.Add(Task.Run(async () => {
test.IsValid = await test.TestValidityAsync();
await pct.PauseOrCancelIfRequested();
}));
}
await Task.WhenAll(tasks);
var validTests = from test in tests
where test.IsValid
select test;
var count = 0;
//Test proxies with a random, valid proxy judge. If valid, test with all valid proxy tests.
tasks.Clear();
foreach (var proxy in proxies)
{
tasks.Add(Task.Run(async () =>
{
proxy.IsValid = await proxy.TestValidityAsync(validJudges.ElementAt(RandomUtility.GetRandomInt(0, validJudges.Count())));
count++;
Console.WriteLine(count);
await pct.PauseOrCancelIfRequested();
if (proxy.IsValid)
{
proxy.TestedSites.AddRange(validTests);
var childTasks = new List<Task>();
foreach (var test in validTests)
{
childTasks.Add(Task.Run(async () =>
{
proxy.TestedSites.ElementAt(proxy.TestedSites.IndexOf(test)).IsValid = await proxy.TestValidityAsync(test);
await pct.PauseOrCancelIfRequested();
}));
}
await Task.WhenAll(childTasks);
}
}));
}
await Task.WhenAll(tasks);
}
}
In general, code in ProxyTester.Start uses pause token this way:
foreach (var judge in judges)
{
tasks.Add(Task.Run(async () => {
judge.IsValid = await judge.TestValidityAsync();
await pct.PauseOrCancelIfRequested();
}));
}
This runs judges.Length number of tasks. What happens when you pause token? Well, nothing useful actually. All tasks continue to run, and all of them will complete their useful work (await judge.TestValidityAsync()). Then, when all useful work is done, and they should just complete - they will pause on await pct.PauseOrCancelIfRequested(). I doubt that is the result you desire. Changing the order won't help much.
Compare that to "working" example:
for (int i = 0; i < 10000; i++)
{
Console.WriteLine(i);
await Task.Delay(1000);
await pct.PauseOrCancelIfRequested();
}
Here execution is sequential (and not parallel like above) and you check pause token every iteration, so it works as expected.
If you want to be able to pause in your real world scenario - don't start all those tasks at once, run them in batches (with SemaphoreSlim or similar technique), and check pause token after each batch.

C# Discord Bot Coding: Creating a command that spams messages then stops with another command

I just need a working line of code that spams a message every five seconds then stops after another command is entered. Like for an example, if a user enters "~raid" then the bot will spam "RAID RAID" every five seconds and stops when the user does "~stop". If anyone could help that'd be awesome.
Here is what I got so far:
class MyBot
{
DiscordClient discord;
CommandService commands;
public MyBot()
{
discord = new DiscordClient(x =>
{
x.LogLevel = LogSeverity.Info;
x.LogHandler = Log;
});
discord.UsingCommands(x =>
{
x.PrefixChar = '~';
x.AllowMentionPrefix = true;
});
commands = discord.GetService<CommandService>();
commands.CreateCommand("checked")
.Do(async (e) =>
{
commands.CreateCommand("weewoo")
.Do(async (e) =>
{
await e.Channel.SendMessage("**WEE WOO**");
});
discord.ExecuteAndWait(async () =>
{
await discord.Connect("discordkeyhere", TokenType.Bot);
});
}
public void Log(object sender, LogMessageEventArgs e)
{
Console.WriteLine(e.Message);
}
}
}
Here is a small example how you could do it.
In this case, you can Start and Stop your bot from outside using the methods Start and Stop.
class MyBot
{
public MyBot()
{
}
CancellationTokenSource cts;
public void Start()
{
cts = new CancellationTokenSource();
Task t = Task.Run(() =>
{
while (!cts.IsCancellationRequested)
{
Console.WriteLine("RAID RAID");
Task.Delay(5000).Wait();
}
}, cts.Token);
}
public void Stop()
{
cts?.Cancel();
}
}
Here is the code to test the MyBot class
static void Main(string[] args)
{
try
{
var b = new MyBot();
while (true)
{
var input = Console.ReadLine();
if (input.Equals("~raid", StringComparison.OrdinalIgnoreCase))
b.Start();
else if (input.Equals("~stop", StringComparison.OrdinalIgnoreCase))
b.Stop();
else if (input.Equals("exit", StringComparison.OrdinalIgnoreCase))
break;
Task.Delay(1000);
}
}
catch (Exception)
{
throw;
}
}

Sockets, Nullreference Exception

I am trying to use web socket with my bot to communicate with the server. But on run time it throws the System.NullReferenceException. I am running socket in background on a different thread so that it does not interfear with the bot.
I am using WebsocketSharp library.
First message comes in just fine but on second message it throws exception at following line in HumanCollaboratorDialog class.
await context.PostAsync(e.Data);
My Socket Stream Class is as following:
public static class SocketStream
{
public static WebSocket ws;
private static List<string> serverMsg = new List<string>();
public static void initializeSocket()
{
ws = new WebSocket("ws://Some IP:8080/human-collaborator/data");
Debug.WriteLine("****** INITIALIZED SOCKET (should happen only once) *****");
Task.Run(() => startSocketStream());
}
private static void startSocketStream()
{
int attempts = 0;
while (!ws.IsAlive)
{
try
{
attempts++;
ws.Connect();
}
catch (WebSocketException)
{
Debug.WriteLine("Connection attempts: " + attempts.ToString());
}
}
ws.OnOpen += (sender, args) =>
{
Debug.WriteLine("# SOCKET OPENED");
};
ws.OnError += (sender, args) =>
{
Debug.WriteLine("# SOME ERROR OCCURED");
};
ws.OnClose += (sender, args) =>
{
Debug.WriteLine("# SOCKET CLOSED");
};
}
}
I am calling the initializeSocket() method in Global.asx to run it on application level
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
SocketStream.initializeSocket();
}
}
My HumanCollaboratorDialog class is as following:
[Serializable]
public class HumanCollaboratorDialog : IDialog<object>
{
public async Task StartAsync(IDialogContext context)
{
context.Wait(this.MessageReceivedAsync);
}
private async Task MessageReceivedAsync(IDialogContext context, IAwaitable<IMessageActivity> result)
{
var message = await result;
SocketStream.ws.OnMessage += async (sender, e) =>
{
try
{
await context.PostAsync(e.Data);
}
catch (HttpRequestException ex)
{
throw ex;
}
};
Thread.Sleep(500);
string output = message.Text;
SocketStream.ws.Send(output);
Thread.Sleep(500);
context.Wait(MessageReceivedAsync);
}
}
My MessagesController has following POST method:
public virtual async Task<HttpResponseMessage> Post([FromBody]Activity activity)
{
if (activity.Type == ActivityTypes.Message)
{
await Conversation.SendAsync(activity, () => new HumanCollaboratorDialog());
}
else
{
HandleSystemMessage(activity);
}
var response = Request.CreateResponse(HttpStatusCode.OK);
return response;
}
Neithet e.Data nor context is empty. I think problem is with socket connection or may be i am doing something wrong in SocketStream class. following is the image
Your bot is a web service. Messages are sent to the service by the client (a web page, an application, another service, etc.) and received in the MessagesController's Post method. There's no need to have the socket code on the server for what you're trying to do. Web Sockets are useful for receiving messages on a client from the bot via a Direct Line connection.
Here is an example of using the Bot Framework's Direct Line Client and creating a web socket connection. Notice how the web socket is created from a conversation's StreamUrl:
DirectLineClientCredentials creds = new DirectLineClientCredentials(directLineSecret);
DirectLineClient directLineClient = new DirectLineClient(creds);
Conversation conversation = await directLineClient.Conversations.StartConversationAsync();
using (var webSocketClient = new WebSocket(conversation.StreamUrl))
{
webSocketClient.OnMessage += WebSocketClient_OnMessage;
webSocketClient.Connect();
while (true)
{
string input = Console.ReadLine().Trim();
if (input.ToLower() == "exit")
{
break;
}
else
{
if (input.Length > 0)
{
Activity userMessage = new Activity
{
From = new ChannelAccount(fromUser),
Text = input,
Type = ActivityTypes.Message
};
await directLineClient.Conversations.PostActivityAsync(conversation.ConversationId, userMessage);
}
}
}
}
private static void WebSocketClient_OnMessage(object sender, MessageEventArgs e)
{
// avoid null reference exception when no data received
if (string.IsNullOrWhiteSpace(e.Data))
{
return;
}
var activitySet = JsonConvert.DeserializeObject<ActivitySet>(e.Data);
var activities = from x in activitySet.Activities
where x.From.Id == botId
select x;
foreach (Activity activity in activities)
{
Console.WriteLine(activity.Text);
}
}
This is from a console application that is using the Direct Line to communicate with the Bot and is listening for messages using web sockets here:
https://github.com/Microsoft/BotBuilder-Samples/tree/master/CSharp/core-DirectLineWebSockets

Categories