async causes debugger jump - c#

I have this code:
private async Task<DataSharedTheatres.TheatresPayload> GetTheatres()
{
var callMgr = new ApiCallsManager();
var fileMgr = new FileSystemManager();
string cachedTheatres = fileMgr.ReadFile(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TheatreTemp.txt"));
if (string.IsNullOrEmpty(cachedTheatres))
{
**string generalModelPull = await callMgr.GetData(new Uri("somecrazyapi.com/api" + apiAccessKey));**
bool saveResult = fileMgr.WriteToFile(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TheatreTemp.txt"), generalModelPull);
if (!saveResult)
{
testText.Text = "Failed to load Theatre Data";
return null;
}
cachedTheatres = fileMgr.ReadFile(Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TheatreTemp.txt"));
}
return Newtonsoft.Json.JsonConvert.DeserializeObject<DataSharedTheatres.TheatresPayload>(cachedTheatres);
**}**
I set the breakpoint on the first highlighted line (which it hits), then I press F10, and debugger jumps to the last bracket! I am not understanding why.
GetData method:
public async Task<string> GetData(Uri source)
{
if (client.IsBusy)
client.CancelAsync ();
string result = await client.DownloadStringTaskAsync (source);
return result;
}

Because that's what "await" does. When you use "await" in an async method, it tells the compiler that you want the method to return at that point, and then to re-enter the method later only when the "awaited" task has completed.

Related

How to detect code running forever when using CSharpScript.EvaluateAsync?

I would like to compile and execute code from a string. Calling the method ExecuteCode() successfully works and returns a string value. However, calling ExecuteEndlessCode() hangs the Console application. How can I detect that CSharpScript.EvaluateAsync is potentially executing code that is running forever?
public static string ExecuteEndlessCode()
{
var script = #"string Run() { while(true){} return ""1"";} Run()";
var result = CSharpScript.EvaluateAsync<string>(script, null).Result;
return result;
}
public static string ExecuteCode()
{
var script = #"string Run() { return ""1"";} Run()";
var result = CSharpScript.EvaluateAsync<string>(script, null).Result;
return result;
}
You can set a timeout for the script, and execute the script execution inside a task, like this:
var script = #" int Run() { while(true){} return 1;} Run();";
var task = CSharpScript.EvaluateAsync<string>(script, null)
if (await Task.WhenAny(task, Task.Delay(timeout) != task)
{ // handle timeout
}

Chaining ASYNC tasks within tasks in cmd application causes crash without exception

Edit:
here is my main method
static void Main(string[] args)
{
LogNewOrders();
DataTable initialData = ControllerSqlAgent.SelectQuery(Resources.Controller, Resources.qryGetInitalData);
Console.WriteLine($"|There are {initialData.Rows.Count} orders to check|");
Task.WhenAll(UpdateItemCountsField(initialData));
}
I have a method called UpdateItemCountsField(datatable)
The purpose of this method is to get both:
total cancelled items
total shipped items
private static async Task UpdateItemCountsField(DataTable initialData)
{
try
{
foreach (DataRow row in initialData.Rows)
{
string narvarId = row["NarvarID"].ToString();
int orderedItemCount = (int)row["ItemsOrdered"];
int totalShippedItems = (int)row["ItemsShipped"]; ;
int totalCancelledItems = (int)row["ItemsCancelled"];
string locateConstraint = GetLocateInConstraint(row["OrderNumber"].ToString(), row["CompanyNumber"].ToString());
Task<int> totalShippedItemsTask = CheckShipmentCountsAsync(locateConstraint, row["OrderNumber"].ToString(), row["CompanyNumber"].ToString(), totalShippedItems, narvarId);
Task<int> totalCancelledItemsTask = CheckCancellationCountsAsync(locateConstraint, row["OrderNumber"].ToString(), row["CompanyNumber"].ToString(), totalCancelledItems, narvarId); ;
int[] result = await Task.WhenAll(totalShippedItemsTask, totalCancelledItemsTask);
//totalShippedItems = CheckShipmentCounts(locateConstraint, row["OrderNumber"].ToString(), row["CompanyNumber"].ToString(), totalShippedItems, narvarId);
//totalCancelledItems = CheckCancellationCounts(locateConstraint, row["OrderNumber"].ToString(), row["CompanyNumber"].ToString(), totalCancelledItems, narvarId);
Console.WriteLine($"|ID:{narvarId}|Ordered: {orderedItemCount}|Shipped: {result[0]}|Cancelled: {result[1]}|");
Console.WriteLine("|___________________________________________|");
}
}
catch
{
throw;
}
}
I have two Task objects that I obtain from async methods:
Task<int> totalShippedItemsTask = CheckShipmentCountsAsync(params);
Task<int> totalCancelledItemsTask = CheckCancellationCountsAsync(params);
Then i get my results like so (this is where the program crashes)
int[] result = await Task.WhenAll(totalShippedItemsTask,totalCancelledItemsTask);
within CheckShipmentCoutnsAsync(params) and CheckCancellationCountsAsync(params) are two more Task<int> objects . This is due to there being two data sources that i have to pull from
private static async Task<int> CheckShipmentCountsAsync(string locateConstraint, string orderNumber, string companyNumber, int currentShippedItemCount, string narvarId)
{
Task<int> wmsShippedCountTask = WmsSqlAgent.GetCountOfShippedItemsAsync(orderNumber, companyNumber);
Task<int> locateShippedCountTask = LocateSqlAgent.GetCountOfShippedItemsAsync(locateConstraint);
int[] result = await Task.WhenAll(wmsShippedCountTask, locateShippedCountTask);
int newShippedItemCount = result.Sum();
if (newShippedItemCount > currentShippedItemCount)
ControllerSqlAgent.UpdateShippedItemCount(narvarId, newShippedItemCount);
return newShippedItemCount;
}
The method CheckCancelCountsAsync(PARAMS) is the same as the above but for cancellations.
When my program runs, It hits the task and then crashes without any exception and never reaches the next datarow to perform the asynchronous methods on. Am I missing a piece here? Why would my application crash without an exception. the reason I believe it is crashing due to the fact that it never makes it to the Console.Writeline(); right after i get the result array from Task.WhenAll
And here is the data source method that retrieves the actual count
internal static async Task<int> GetCountOfCancelledItemsAsync(string orderNumber, string companyNumber)
{
int itemCount = 0;
await Task.Run(() =>
{
try
{
using (var connection = new SqlConnection(Resources.WMS))
{
connection.Open();
using (var command = new SqlCommand(Resources.qryWmsGetCancelledItemCount, connection))
{
command.Parameters.AddWithValue("#orderNumber", orderNumber);
command.Parameters.AddWithValue("#companyNumber", companyNumber);
itemCount = int.Parse(command.ExecuteScalar().ToString());
}
connection.Close();
}
}
catch (SqlException E)
{
string message = E.Message;
throw;
}
return itemCount;
});
return itemCount;
While stepping through the code I can see that my program crashes when i get to nt[] result = await Task.WhenAll(totalShippedItemsTask, totalCancelledItemsTask); but still no exception.
You have not awaited the results of Task.WhenAll(UpdateItemCountsField(initialData)) in your main method. This means that the program will exit without waiting for that code to finish executing.
Change your method to this:
static async Task Main(string[] args)
{
LogNewOrders();
DataTable initialData = ControllerSqlAgent.SelectQuery(Resources.Controller, Resources.qryGetInitalData);
Console.WriteLine($"|There are {initialData.Rows.Count} orders to check|");
await UpdateItemCountsField(initialData);
}
Since UpdateItemCountsField returns a single Task, the Task.WhenAll wrapping it was redundant, so I removed that from the code in my answer.
Note that you must be using C# 7.1 or later in order to have an async main method.
Make sure on any method that returns a Task that you await the result.

Async behaving sync while debugging?

Something is definitely flawed in my understanding of async/await. I want a piece of code named SaveSearchCase to run asynchronously in background.
I want it to be fired and forget about it and continue with the current method's return statement.
public IList<Entities.Case.CreateCaseOutput> createCase(ARC.Donor.Data.Entities.Case.CreateCaseInput CreateCaseInput, ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput)
{
..........
..........
..........
var AcctLst = rep.ExecuteStoredProcedure<Entities.Case.CreateCaseOutput>(strSPQuery, listParam).ToList();
if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
{
Task<IList<Entities.Case.SaveCaseSearchOutput>> task = saveCaseSearch(SaveCaseSearchInput, AcctLst.ElementAt(0).o_case_seq);
Task t = task.ContinueWith(
r => { Console.WriteLine(r.Result); }
);
}
Console.WriteLine("After the async call");
return AcctLst;
}
And the SaveCaseSearch looks like
public async Task<IList<Entities.Case.SaveCaseSearchOutput>> saveCaseSearch(ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
Repository rep = new Repository();
string strSPQuery = string.Empty;
List<object> listParam = new List<object>();
SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key,out strSPQuery, out listParam);
var AcctLst = await rep.ExecuteStoredProcedureAsync<Entities.Case.SaveCaseSearchOutput>(strSPQuery, listParam);
return (System.Collections.Generic.IList<ARC.Donor.Data.Entities.Case.SaveCaseSearchOutput>)AcctLst;
}
But when I see the debugger createCase method waits for SaveCaseSearch to complete first and then only
it prints "After Async Call "
and then returns . Which I do not want definitely .
So which way is my understanding flawed ? Please help to make it run async and continue with current method's print and return statement .
UPDATE
I updated the SaveCaseSearch method to reflect like :
public async Task<IList<Entities.Case.SaveCaseSearchOutput>> saveCaseSearch(ARC.Donor.Data.Entities.Case.SaveCaseSearchInput SaveCaseSearchInput,Int64? case_key)
{
return Task.Run<IList<Entities.Case.SaveCaseSearchOutput>>(async (SaveCaseSearchInput, case_key) =>
{
Repository rep = new Repository();
string strSPQuery = string.Empty;
List<object> listParam = new List<object>();
SQL.CaseSQL.getSaveCaseSearchParameters(SaveCaseSearchInput, case_key, out strSPQuery, out listParam);
var AcctLst = await rep.ExecuteStoredProcedureAsync<Entities.Case.SaveCaseSearchOutput>(strSPQuery, listParam);
return (System.Collections.Generic.IList<ARC.Donor.Data.Entities.Case.SaveCaseSearchOutput>)AcctLst;
});
}
But there is something wrong with the params. It says
Error 4 A local variable named 'SaveCaseSearchInput' cannot be declared in this scope because it would give a different meaning to 'SaveCaseSearchInput', which is already used in a 'parent or current' scope to denote something else C:\Users\m1034699\Desktop\Stuart_V2_12042016\Stuart Web Service\ARC.Donor.Data\Case\Search.cs 43 79 ARC.Donor.Data
Well this saveCaseSearch() method runs synchronously in main thread and this is the main problem here. Instead of returning result with a task you should return Task with operation itself. Here is some simplified example :
Runs synchronously and waits 5 seconds
public IList<int> A()
{
var AcctLst = new List<int> { 0, 2, 5, 8 };
if (true)
{
Task<IList<int>> task = saveCaseSearch();
Task t = task.ContinueWith(
r => { Console.WriteLine(r.Result[0]); }
);
}
Console.WriteLine("After the async call");
return AcctLst;
}
// runs sync and in the end returns Task that is never actually fired
public async Task<IList<int>> saveCaseSearch()
{
Thread.Sleep(5000);
return new List<int>() { 10, 12, 16 };
}
Runs asynchronously - fires task & forgets :
public IList<int> A()
{
... same code as above
}
// notice that we removed `async` keyword here because we just return task.
public Task<IList<int>> saveCaseSearch()
{
return Task.Run<IList<int>>(() =>
{
Thread.Sleep(5000);
return new List<int>() { 10, 12, 16 };
});
}
Here is full code for this example
Against all that I believe in pertaining to "fire-and-forget" you can do this by writing your code this way:
public Task<SaveCaseSearchOutput> SaveCaseSearch(
SaveCaseSearchInput saveCaseSearchInput,
long? caseKey)
{
var rep = new Repository();
var query = string.Empty;
var listParam = new List<object>();
SQL.CaseSQL
.getSaveCaseSearchParameters(
saveCaseSearchInput,
caseKey,
out query,
out listParam);
return rep.ExecuteStoredProcedureAsync<SaveCaseSearchOutput>(
strSPQuery,
istParam);
}
And then if the place where you would like to fire it and log when it returns (which is really what you have -- so you're not forgetting about it), do this:
public IList<CreateCaseOutput> CreateCase(
CreateCaseInput createCaseInput,
SaveCaseSearchInput saveCaseSearchInput)
{
// Omitted for brevity...
var AcctLst =
rep.ExecuteStoredProcedure<CreateCaseOutput>(
strSPQuery,
listParam)
.ToList();
if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
{
SaveCaseSearch(saveCaseSearchInput,
AcctLst.ElementAt(0).o_case_seq)
.ContinueWith(r => Console.WriteLine(r.Result));
}
Console.WriteLine("After the async call");
return AcctLst;
}
The issue was that you were using async and await in the SaveSearchCase function, and this basically means that your code is the opposite of "fire-and-forget".
As a side note, you should really just use async and await, and avoid the "fire-and-forget" idea! Make your DB calls asynchronous and leverage this paradigm for what it's worth!
Consider the following:
The SaveCaseSearch call can stay as I have defined it above.
public Task<SaveCaseSearchOutput> SaveCaseSearch(
SaveCaseSearchInput saveCaseSearchInput,
long? caseKey)
{
var rep = new Repository();
var query = string.Empty;
var listParam = new List<object>();
SQL.CaseSQL
.getSaveCaseSearchParameters(
saveCaseSearchInput,
caseKey,
out query,
out listParam);
return rep.ExecuteStoredProcedureAsync<SaveCaseSearchOutput>(
strSPQuery,
istParam);
}
Then in your call to it, do this instead:
public async Task<IList<CreateCaseOutput>> CreateCase(
CreateCaseInput createCaseInput,
SaveCaseSearchInput saveCaseSearchInput)
{
// Omitted for brevity...
var AcctLst =
await rep.ExecuteStoredProcedureAsync<CreateCaseOutput>(
strSPQuery,
listParam)
.ToList();
if (!string.IsNullOrEmpty(AcctLst.ElementAt(0).o_case_seq.ToString()))
{
await SaveCaseSearch(saveCaseSearchInput,
AcctLst.ElementAt(0).o_case_seq)
.ContinueWith(r => Console.WriteLine(r.Result));
}
Console.WriteLine("After the async call");
return AcctLst;
}
This makes for a much better solution!

Is Object created before or after method calls?

I have three different databases that I need to check that I am connected to. This is what I originally have, which works perfectly fine.
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
return new ServiceAvailabilityDTO
{
IsDb1Online = await IsDb1Available(),
IsDb2Online = IsDb2Available(),
IsDb3Online = await IsDb3Available()
};
}
private async Task<bool> IsDb1Available()
{
var count = await _db1Service.GetDbCount();
if (count > 0)
return true;
return false;
}
private bool IsDb2Available()
{
if (_db2Service.GetDbCount() > 0)
return true;
return false;
}
private async Task<bool> IsDb3Available()
{
var pong = await _db3Provider.PingDb();
if(pong.Success == true && pong.Version != null)
return true;
return false;
}
Now however, I need to log exception messages in my DTO for each DB check.
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
return new ServiceAvailabilityDTO
{
IsDb1Online = await IsDb1Available(),
IsDb2Online = IsDb2Available(),
IsDb3Online = await IsDb3Available(this) // This is an example. I want to pass the reference of **ServiceAvailabilityDTO** to **IsDb3Available**
};
}
private async Task<bool> IsDb3Available(ServiceAvailabilityDTO availability)
{
try
{
var pong = await _db3Provider.PingDb();
if(pong.Success == true && pong.Version != null)
return true;
return false;
}
catch (Exception e)
{
var exceptionMessage = e.Message;
if (e.InnerException != null)
{
// This is what I hope to put into the object reference
exceptionMessage = String.Join("\n", exceptionMessage, e.InnerException.Message);
availability.db3Exception = exceptionMessage ;
}
return false;
}
}
My question is;
Can I keep my return method the same as in the first example, and pass the object reference to each method to store the exception and still return my bool value.
Or does the object not get created until all of the method calls have happened, and then create the object with the returned values?
I know I could just create the object normally and pass it in each
method call, but it is specifically this way of doing it that has
inspired me to ask this question, purely to be informed and learn
from.
Thanks.
No, you cannot do it like this because in the context of what you're doing this does not refer to the object you're populating, it refers to the object containing the method you're calling.
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
return new ServiceAvailabilityDTO
{
IsDb1Online = await IsDb1Available(),
IsDb2Online = IsDb2Available(),
IsDb3Online = await IsDb3Available(this) // here 'this' does NOT ref to ServiceAvailabilityDTO
};
}
There is no keyword which does refer to ServiceAvailabilityDTO either, so you're left with creating the object, and passing it to each method. At this point, I dont think there is much point you returning the boolean either - you may as well set the boolean property in line
public async Task<ServiceAvailabilityDTO> ServiceAvailabilityStatus()
{
var sa = new ServiceAvailabilityDTO();
await CheckDb1Available(sa);
CheckDb2Available(sa);
await CheckDb3Available(sa);
return sa;
}
(Note I've renamed the methods from Is* to Check* as the former implies a return boolean, the latter implies something going on inline.)

Async await how to use return values

I have a windows service that I have inherited from another developer, it runs very slow and has numerous slow call to the eBay API. I wish to speed it up without too much refactoring.
I've just started to look at using c# async/await to try to get some of these slow call to run async.
Here's what i'm trying to achieve:
I have a 1 very busy method that makes lots of calls as below:
getProducts
getCategories
getVehicles
getImages
My thoughts were that I could simply change the methods to async and add Task<T> to the return type as below:
public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem)
{
String additionalProductDetails = string.Empty;
if (oItem.ItemSpecifics.Count > 0)
{
foreach (NameValueListType nvl in oItem.ItemSpecifics)
{
if (nvl.Value.Count > 0)
{
foreach (string s in nvl.Value)
{
additionalProductDetails += "<li><strong>" + nvl.Name + ":</strong> " + s + "</li>";
}
}
}
}
return additionalProductDetails;
}
Then call them with await:
Task<String> additionalProductDetials = ebayPartNumbers.ProcessAdditionalProductDetialsAsync(item);
Task<PartNumberCollection> partNumberCollection = ebayPartNumbers.ProcessPartNumbersAsync(item);
await Task.WhenAll(partNumberCollection, additionalProductDetials);
How do I get hold of the returned types so I can use them? I have tried just using partNumberCollection but it only has the await properties available.
Use Result property on Task class:
await Task.WhenAll(partNumberCollection, additionalProductDetials);
var partNumberCollectionResult = partNumberCollection.Result;
var additionalProductDetialsResult = additionalProductDetials.Result;
If the task returned by Task.WhenAll has completed, that means all of the tasks that you passed to it have completed too. That in turn means that you can use the Result property of each task, with no risk of it blocking.
string details = additionalProductDetials.Result;
Alternatively, you could await the tasks, for consistency with other async code:
string details = await additionalProductDetials;
Again, this is guaranteed not to block - and if you later remove the Task.WhenAll for some reason (e.g. you're happy to use the details to kick off another task before you've got the part number collection) then you don't need to change the code.
Your async method lacks of await operators and will run synchronously. while you are calling non blocking API you could use Task.Run() to do cpu-bound work on background thread.
public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem)
{
return await Task.Run(() =>
{
String additionalProductDetails = string.Empty;
if (oItem.ItemSpecifics.Count > 0)
{
foreach (NameValueListType nvl in oItem.ItemSpecifics)
{
if (nvl.Value.Count > 0)
{
foreach (string s in nvl.Value)
{
additionalProductDetails += "<li><strong>" + nvl.Name + ":</strong> " + s + "</li>";
}
}
}
}
return additionalProductDetails;
});
}
and get result
var detail = await ProcessAdditionalProductDetialsAsync(itemType);
var result = ProcessAdditionalProductDetialsAsync(itemType).Result;
Try this code:
public async Task<String> ProcessAdditionalProductDetialsAsync(ItemType oItem) {
String additionalProductDetails = await Task.Run(() => {
if (oItem.ItemSpecifics.Count > 0) {
foreach (NameValueListType nvl in oItem.ItemSpecifics) {
if (nvl.Value.Count > 0) {
string retval = String.Empty;
foreach (string s in nvl.Value) {
retval += "<li><strong>"
+ nvl.Name + ":</strong> " + s + "</li>";
}
}
}
}
return retval;
}
return additionalProductDetails;
}
Usage:
private async void GetAdditionalProductDetailsAsync(Action<string> callback) {
string apd = await ProcessAdditionalProductDetialsAsync();
callback(apd);
}
private void AdditionalProductDetailsRetrieved(string apd) {
// do anything with apd
}

Categories