Async and Await loops in C #
If you program an infinite loop in C #, then you have to install await in the asynchronous method.
These only work if you define the method to call with async Task <>.
Defining the asynchronous method with async void does not wait for true asynchronous operations
Program infinite loop with real await
1) Proper Async / Await setup
Right: with await
This little C # Code example contains a while-infinite loop, which waits for the result of reading a web page.
The call is made asynchronously with the abbreviation: await before the method.
That is, the program and also the debugger wait until the call of the method comes back.
//----< @Loop: Alle Empty Records >---- while (1==1) { //----< Detail >---- if (optStop.IsChecked == true) return;
//< find record > string sSQL = "SELECT [IDDetail] FROM tbl_Details WHERE [dtScan] IS NULL LIMIT 1"; SqliteDataReader dataReader = clsDB.Get_DataReader(sSQL); //</ find record > if (dataReader.HasRows) { dataReader.Read(); await Scrape_Detail_byIDProjekt(Convert.ToInt32(dataReader["IDDetail"])); } else { fx_Log("no record"); break; } //----</ Detail >---- }
|
Correct sub-method: with task <..>
However, calling the asynchronous method only works if the method has been defined with async Task <returnType>.
Other definitions with async void do not work.
Private async Task<bool> Scrape_Detail_byIDProjekt(int ID) { //--------< Scrape_Detail() >-------- if (optStop.IsChecked == true) return false;
//fx_Log("--< Read Detail >--"); fx_Log("Detail=" + ID);
string sURL = await clsDB.Get_Value_as_String("URL", "tbl_Details", "[IDDetail]=" + ID); HtmlDocument doc = await Web_Get_HtmlDocument(sURL); //< check > if (doc == null) { fx_Log("doc is NULL ID" + ID ); //< update > string sql_Error = "UPDATE tbl_Details SET [dtScan] = CURRENT_TIMESTAMP WHERE IDDetail = " + ID; //SYSDATETIME() bool bUpdate = await clsDB.Execute_SQL(sql_Error); //</ update > return false; } //</ check > .. } |
Wrong Async / Await construction
Building the loop without Await causes the debugger to always run in a circle without waiting.
This means that if you set a breakpoint to the method or a line, then the debugger always jumps back to itself or the entry point of the method for the Next-Step into-Next buttons (F10, F11, F5).
Mostly one then thinks of the asynchronous method like sHTML = await httpClient.GetStringAsync (sURL); The system would be wrong, but in reality, you have not built a Wait function itself.
Not correct:
//----< @Loop: Alle Empty Records >---- while (1 == 1) { //----< Detail >---- if (optStop.IsChecked == true) return;
//< find record > string sSQL = "SELECT [IDDetail] FROM tbl_Details WHERE [dtScan] IS NULL LIMIT 1"; SqliteDataReader dataReader= clsDB.Get_DataReader(sSQL); //</ find record > if (dataReader.HasRows ) { dataReader.Read(); Scrape_Detail_byIDProjekt(Convert.ToInt32(dataReader["IDDetail"])); } else { break; } //----</ Detail >---- } //----</ @Loop: Alle Empty Records >----
|
And wrong sub-method with void
At the breakpoint, use the method sHTML = await httpClient.GetStringAsync (sURL); the debugger always jumps out of the method.
You have to make sure that you do not declare async void but asyn Task <bool>
private async void Scrape_Detail_byIDProjekt(int ID) { //--------< Scrape_Detail() >-------- if (optStop.IsChecked == true) return;
//fx_Log("--< Read Detail >--"); fx_Log("Detail=" + ID);
string sURL = await clsDB.Get_Value_as_String("URL", "tbl_Details", "[IDDetail]=" + ID); HtmlDocument doc = await Web_Get_HtmlDocument(sURL); //< check > if (doc == null) { //< update > string sql_Error = "UPDATE tbl_Details SET [dtScan] = CURRENT_TIMESTAMP WHERE IDDetail = " + ID; //SYSDATETIME() bool bUpdate=await clsDB.Execute_SQL(sql_Error); //</ update > return; } //</ check > .. } |