I have desktop application in which I am doing some SQL Server queries asynchronously using ADO.NET. There is one case in which I am creating an object and its taking around 5-6 seconds for completion. Now the problem is occurring when I am calling a ADO.NET asynchronous method to fetch data from database. Once it hit await then call is return to main thread without completing other tasks and after some it returning back await but the call is already returned to main thread, due to this I am not getting complete data.
Here is a main caller:
Task.Run<Product>(() => product.GetProduct(item))
.ContinueWith(task =>
{
if (task.IsFaulted)
{
throw;
}
else if (task.Result != null)
{
// here it coming without completing a complete Task
}
})
.ConfigureAwait(false);
GetProduct methods do some more similar Task
public async Task<Product> GetProduct(ProductVariant item)
{
Product product = new Product();
product.Quantity = await GetQuantity(item.Id);
// some other properties
return product
}
The code when it hit it returned to the above task:
public async Task<List<Item>> Test()
{
// preparing query code
sqlDataReader = await sqlCommand.ExecuteReaderAsync();
// code logic after result returned
}
How can I make it so that returned a complete Task?
Based on the code and the comments you should await product.GetProduct(item) call plus I don't know the need of creating a Task (Task.Run and await it) just for it when you probably need the returned Product synchronously.
Your best bet is:
Product retProduct = await product.GetProduct(item);
if (retProduct != null)
{
// Do your logic
}
else
{
// Handle it
}
Related
Simply I want to make an external call to external api which has SenMessageAsync(string message) method and i need to return my client Ok() without waiting it to finish. But on the backend side I need to response of SendMessageAsync() method for continue some process. I mean somehow I need to await it.
Example
try
{
//...
var response = await SendMessageAsync("test"); //dont wait the response, return Ok()
//do something with response
}
catch(MyException ex)
{
//Log
}
catch(Exception ex)
{
//Log
}
Update:
I am updating with one solution I found. Task.Run() (which called fire and forget). Maybe it helps someone. Thanks for answers.
Solution 1:
_ = Task.Run(() => SendMessageAsync(), task =>
{
//We can have exception here if SendMessageAsync() fails
var exception = task.InnerException.Exception;
//Log the exception
}, TaskContinuationOptions.OnlyOnFaulted)
You need a basic distributed architecture, as described on my blog. In summary:
A durable queue. Serialize the work to be done into this queue (e.g., { "operation" = "SendMessage", "data" = "test" }).
A separate backend processor that reads from that queue and does the actual work (e.g., SendMessageAsync(message.data)).
Your backend processor can await the call to SendMessageAsync and then do further processing.
You can use the Task.Run method to run the SendMessageAsync method asynchronously on a separate thread. You can then return Ok() to the client immediately, while the SendMessageAsync method continues to run in the background. To wait for the result of the SendMessageAsync method, you can use the await keyword within the Task.Run method.
Here's an example:
public async Task<IActionResult> MyAction()
{
// Return Ok() immediately to the client
_ = Task.Run(async () =>
{
// Run SendMessageAsync asynchronously on a separate thread
var result = await SendMessageAsync("My message");
// Continue processing using the result of SendMessageAsync
// ...
});
return Ok();
}
I have an async function that edits a database in C#
public async Task DeleteEntry(int Id)
{
var toDeleteEntry = (await firebase
.Child("Entries")
.OnceAsync<Entry>()).Where(a => a.Object.id == Id).FirstOrDefault();
await firebase.Child("Entries").Child(toDeleteEntry.Key).DeleteAsync();
}
If I call this function in a loop without having a wait function (commented out below)
foreach (Entry entry in allData)
{
var task = DeleteEntry(entry.id);
//task.Wait();
}
Will it:
Error out?
Create a new thread for each task?
Create only 1 thread and block until that thread finishes the next time it iterates the loop?
Please explain.
Not Throw any Exception. its Work Synchronously First Function Call Then Move To Next Iteration.
if you want to run in Thread Then use
public async Task DeleteEntry(int Id)
{
var toDeleteEntry = (await firebase
.Child("Entries")
.OnceAsync<Entry>()).Where(a => a.Object.id == Id).FirstOrDefault();
await firebase.Child("Entries").Child(toDeleteEntry.Key).DeleteAsync();
}
Want To Run With Task Then Use This Code. Its Execute The Method Parallels Thread
var task = Task.Run(() => DeleteEntry(entry.id));
I am working on a web api project in which user perform some action and all the related user get notification regarding the user activity. To notify every user i am starting a new thread which perform the desire action. is it necessary to wait for this thread to terminate before request gets complete and return result to user.
P.S. Execution time for thread may increase with no of user.
Please Suggest any alternate if possible
Program Logic(Presently i am using await function to wait for async function to execute)
public async Task<IHttpActionResult> doSomething(arguments)
{
.
.
.
.
<!-- Perform some operation which includes some database transcations--!>
if(operation succesed)
{
await Notification(userid);
}
return result;
}
static void Main(string[] args)
{
var userIds = new[] { 1, 2, 3, 4, 5};
Console.WriteLine("Updating db for users...");
// Start new thread for notficiation send-out
Task.Run(() =>
{
foreach (var i in userIds)
Console.WriteLine("Sending notification for #user " + i);
}).ContinueWith(t => Console.WriteLine("Notifcation all sent!"));
Console.WriteLine("Return the result before notification all sent out!");
}
If you remove await in front of Task.Run() (equivalent to Notifcation() which returns Task<> in your case) and run then it will create separate thread for notification send-out.
public async Task<IHttpActionResult> doSomething(arguments)
{
bool isInsertDone ,isUpdateDone = false;
//create thread list
var task = new List<Task>();
// parallel tasks to thread list and execute that tasks
task.Add(Task.Run(() =>
{`enter code here`
isInsertDone = insertData(arguments)
}));
task.Add(Task.Run(() =>
{
isUpdateDone updateData(arguments)
}));
// wait for execute all above tasks
Task.WaitAll(task.ToArray());
// return response by result of insert and update.
return Ok<bool>(isInsertDone && isUpdateDone);
}
If it is going to be a long running function and there is no direct impact on the current function then there is no need to wait. Fire and forget. You can safely remove the await.
public async Task<IHttpActionResult> doSomething(arguments) {
//... Perform some operation which includes some async database transactions
if(operation succesed) {
NotificationsAsync(userid); //Start notifications and continue
}
return result;
}
I would suggest using a messaging queue for jobs like that but that is a more advanced topic which is out of scope for this question.
I had a complex Task/lock based mess for performing a 'long' data operation, and I'm trying to replace it with an async/await. I'm new to async await, so I'm worried I'm making some big mistakes.
To simplify things, my UI has a few pages that depend on the same data. Now, I only need to get this data once. So I cache it, and further calls just grab it from the cache "CachedDataObjects" rather than doing the long call every time.
Like this (semi-pseudocode):
private Dictionary<Guid,List<Data>> CachedDataObjects;
public async Task<List<Data>> GetData(Guid ID)
{
List<Data> data = null;
//see if we have any cached
CachedDataObjects.TryGetValue(ID, out data);
if (data == null)
{
if (ConnectedToServer)
{
data = new List<Data>();
await Task.Run(() =>
{
try
{
//long data call
data = Service.GetKPI(ID);
}
catch (Exception e)
{
//deal with errors (passes an action to do if resolved)
PromptForConnection(new Task(async () => { data = await GetData(ID); }), e);
}
});
}
CachedDataObjects.Add(ID, data);
}
return data;
}
However, by the nature of the asynchronous calls, this method get's called by the two pages when they are triggered.
As a result, there's an exception - an item with the ID has already been added to the dictionary. Even if I patched that problem, the underlying issue is still there. The Data objects would be different versions, I'm doing two network calls where I should only have one etc.
Previously, I 'hacked' a solution by encapsulating the whole method in a lock statement - thereby only allowing a single call to it. All my data loading being done in background workers, the first did the call, and once it had finished the others were then unlocked to perform the quick grab.
But I can't use lock in an asynchronous method, and the solution didn't feel good anyway.
Is there any way with asynchronous methods to 'wait' on other asynchronous calls to finish?
Your problem is that you're awaiting the task before adding it to the dictionary. In this case, you'll want to add the task to the dictionary, so that the next page calling this method will get the same task:
public Task<List<Data>> GetData(Guid ID)
{
Task<List<Data>> task = null;
CachedDataObjects.TryGetValue(ID, out task);
if (task == null)
{
if (ConnectedToServer)
{
task = Task.Run(() =>
{
try
{
//long data call
return Service.GetKPI(ID);
}
catch (Exception e)
{
//deal with errors
}
});
}
DataObjects.Add(ID, task);
}
return task;
}
This will cache the task. However, if //deal with errors propagates exceptions, then this will cache that exception as well.
To avoid this, you can use more complex code, or you can adopt my AsyncLazy<T> type:
private readonly ConcurrentDictionary<Guid, AsyncLazy<List<Data>>> CachedDataObjects;
public Task<List<Data>> GetData(Guid ID)
{
var lazy = CachedDataObjects.GetOrAdd(ID, id =>
new AsyncLazy<List<Data>>(() => Task.Run(() =>
{
try
{
return Service.GetKPI(ID);
}
catch (Exception e)
{
//deal with errors
throw;
}
}, AsyncLazyFlags.RetryOnFailure | AsyncLazyFlags.ExecuteOnCallingThread)));
return lazy.Task;
}
This is for an iOS app written in Xamarin. All my application code runs in the main thread (i.e. the UI thread).
The UI code does something as follows:
public async void ButtonClicked()
{
StartSpinner();
var data = await UpdateData();
StopSpinner();
UpdateScreen(data);
}
The UpdateData function does something as follows:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
TriggerCacheUpdate();
return data;
}
TriggerCacheUpdate ends up calling the following function defined below
public Task RefreshCache()
{
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
}
My question is how should TriggerCacheUpdate be written? The requirements are:
Can't be async, I don't want UpdateData and consequently
ButtonClicked to wait for RefreshCache to complete before
continuing.
UpdateInternalDataStructures needs to execute on the main (UI) thread, i.e. the thread that all the other code shown above executes on.
Here are a few alternatives I came up with:
public void TriggerCacheUpdate()
{
RefreshCache();
}
The above works but generates a compiler warning. Moreover exception handling from RefreshCache doesn't work.
public void TriggerCacheUpdate()
{
Task.Run(async() =>
{
await RefreshCache();
});
}
The above violates requirement 2 as UpdateInternalDataStructures is not executed on the same thread as everything else.
A possible alternative that I believe works is:
private event EventHandler Done;
public void TriggerCacheUpdate()
{
this.task = RefreshCache();
Done += async(sender, e) => await this.task;
}
Task RefreshCache() {
var data = await FetchMoreDataFromServer();
UpdateInternalDataStructures();
if (Done != null) {
Done(this, EventArgs.Empty);
}
}
Does the above work? I haven't ran into any problems thus far with my limited testing. Is there a better way to write TriggerCacheUpdate?
It's hard to say without being able to test it but it looks like your trigger cache update method is fine, it's your RefreshCache that needs to change. Inside of RefreshCache you are not waiting in the UI thread for the result of "data" to return so set the ConfigureAwait to false.
public async Task RefreshCache()
{
var data = await FetchMoreDataFromServer().ConfigureAwait(false);
UpdateInternalDataStructures();
}
Your event handler is async. That means, that even if you await for a Task to complete, that your UI remains responsive. So even if you would await for the TriggerCacheUpdate to return, your UI would remain responsive.
However, if you are really certain that you are not interested in the result of TriggerCachUpdate, then you could start a Task without waiting for it:
public Task<Data> UpdateData()
{
var data = await FetchFromServer();
Task.Run( () => TriggerCacheUpdate());
return data;
}
Note: careful: you don't know when TriggerCachUpdate is finished, not even if it ended successfully or threw an exception. Also: check what happens if you start a new TriggerCacheUpdate task while the previous one is not finished yet.
For those who want to use Task.Factory.StartNew, see the discussion about it in MSDN:
Task.Run vs Task.Factory.StartNew