I have a couple of services running, A and B (both are web api) and an http client. This is the sequence of events I want accomplish asynchronously:
Client calls A and passes an object O as parameter,
A begins async process (P1) to do something with O,
While P1 is running A sends asynchronous message to B [P2] (which may take a while) for B to do something with it. Essentially A is now the client of B
[ this is the important part ]
As soon as P1 is finished doing its work I want A to send OK response back to the calling client,
I don't want to make the client wait until B sends its own response to A before A can respond to the client with an OK,
As far as the client is concerned A does only P1 and that's it, does not care about communication between A and B, it only cares about the results of P1
A should handle whatever response B may send on its own time at its own pace
Both P1 and P2 are async methods, which I have already defined and working
6-9 are only for clarification purposes, but how do I accomplish 5?
I'm working with MS stack, VS2013, C#5
Here is pseudo code I'm trying to implement:
// this is the clinent and where it all begins
class Class1
{
static void Main()
{
using (var client = new HttpClient())
{
var o = new SomeObject();
var response = client.PostAsJsonAsync(api, o);
Console.Write(response.Status);
}
}
}
// this one gets called from the client above
class ServiceA
{
public async Task<IHttpActionResult> Post([FormBody] SomeObject someObject)
{
// this one I want to wait for
var processed = await ProcessSomeObjectA(SomeObject some);
// now, how do I call SendToService so that this POST
// will not wait for completion
SendToService(someObject);
return processed.Result;
}
private async Task<bool> ProcessSomeObjectA(SomeObject some)
{
// whatever it does it returns Task<bool>
return true;
}
private async Task<IHttpActionResult> SendToService(SomeObject someObject)
{
using (var client = new HttpClient())
{
var o = new SomeObject();
var response = await client.PostAsJsonAsync(api, o);
return response.StatusCode == HttpStatusCode.OK;
}
}
}
class ServiceB
{
// this gets called from ServiceA
public async Task<IHttpActionResult> Post([FormBody] SomeObject someObject)
{
return (await ProcessSomeObjectB(someObject))) ? Ok() : BadResponse();
}
private async Task<bool> ProcessSomeObjectB(SomeObject some)
{
// whatever it does it returns Task<bool>
return true;
}
}
Try the following code in service "A":
public async Task<HttpResponseMessage> ServiceAAction()
{
try
{
var client = new HttpClient();
client.GetAsync("http://URLtoWebApi/ServiceB").ContinueWith(HandleResponse);
// any code here will execute immediately because the above line is not awaited
// return response to the client indicating service A is 'done'
return Request.CreateResponse(HttpStatusCode.OK);
}
catch
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
private async void HandleResponse(Task<HttpResponseMessage> response)
{
try
{
// await the response from service B
var result = await response;
// do work
// dont attempt to return anything, service A has already returned a response to the client
}
catch (Exception e)
{
throw;
}
}
I have played with this a little bit. My test client (that consumes "A") receives a response message immediately. The method HandleResponse() is hit after the second api ("B") has finished its work. This setup cannot return a second message back to the client of "A", which is what I believe you are after anyways.
I guess what you want is for the B method to be called in a "fire and forget" way:
public Task TaskA(object o)
{
//Do stuff
//Fire and Forget: call Task B,
//create a new task, dont await
//but forget about it by moving to the next statement
TaskB();
//return;
}
public Task TaskB()
{
//...
}
public async Task Client()
{
var obj = "data";
//this will await only for TaskA
await TaskA(obj);
}
Without an example of what you have. I think you are looking for an Async with callback.
What you'd want to start the call to B without "awaiting" it so you can close your P1 Task and return then you'd want something like this.
Please have a look here, too: Can i use async without await in c#?
I hope that helps.
Related
I have a problem with async/await in C#, i need it to get some object called Trades, after i get it, it needs to SAVE it. Problem is, with async/await, it is doing the SAVE first, and then go and get my trade objects. How do i ensure i get the objects first, and then does the saving.... here is my code...
private async void OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
public async Task<int> OnSaveTrades()
{
foreach (var trade in mmTrades)
{
await ExchangeServiceInstance.OnInsertDoneTrade(trade);
}
return mmTrades.Count;
}
Any ideas guys? Thanks!
The problem is your OnRefresh method. Because the return type is void the method is not awaited [Check out this answer]. In addition you dont even try to await for the method inside your delegate
Changing the method to the following:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
And await this method inside your delegate, should solve your problem:
public async void OnSignalReceived()
{
// THIS NEEDS TO FINISH FIRST, BUT IT DOESN'T
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
await OnRefresh();
}
});
// SOMEHOW THIS GETS CALLED FIRST BEFORE THE ABOVE GETS TO FINISH!
await OnSaveTrades();
}
The use of (Action)async is basically the same as async void, and async void is almost always a mistake. Specifically, the consumer cannot know the outcome (unless it faults synchronously). The dispatcher here isn't really thinking of async.
If we assume that you must use the dispatcher here, perhaps a workaround might be to use something like a SemaphoreSlim (or maybe a TaskCompletionSource<something>) that you signal at the end of your async work (even in the exception case), and then await that; untested, but:
var tcs = new TaskCompletionSource<bool>();
await tradeListView.Dispatcher.InvokeAsync((Action)async delegate
{
try {
if (ExchangeServiceInstance.SelectedTabIndex == CURRENT_TAB_INDEX_ITEM)
{
await Task.Delay(MMConfig.DELAYMILLISEC);
OnRefresh();
}
tcs.TrySetResult(true);
} catch (Exception ex) {
tcs.TrySetException(ex);
}
});
await tcs.Task; // ensure the async work is complete
await OnSaveTrades();
First of all, you are using the async void pattern a lot. This is really bad practice for a number of reasons. You should stop doing that.
The problem here is that OnRefresh is again an async void method that can't be awaited but should be:
private async Task OnRefresh()
{
try
{
var trades = await ExchangeServiceInstance.GetTrades("");
mmTrades = new ObservableCollection<EEtrade>(trades);
tradeListView.ItemsSource = mmTrades;
}
catch { }
}
In your OnSignalReceived method change the call to OnRefresh(); to await OnRefresh();
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();
I'm refactoring old code which does synchronous http requests and returns Callback object with success and fail events. How to properly wrap code into async/await?
I've added HttpClient class and I'm using SendAsync method on which I await, but I'm not sure how properly make transition from await into events. I've added async void Execute method in class but it does not seem like correct way of handling - avoid async void. Below more explanation in (short version of) code.
public class HttpExecutor(){
public event Action<string> Succeed;
public event Action<ErrorType, string> Failed;
private bool isExecuting;
//I know that async void is not the best because of exceptions
//and code smell when it is not event handler
public async void Execute()
{
if (isExecuting) return;
isExecuting = true;
cancellationTokenSource = new CancellationTokenSource();
try
{
httpResponseMessage =
await httpService.SendAsync(requestData, cancellationTokenSource.Token).ConfigureAwait(false);
var responseString = string.Empty;
if (httpResponseMessage.Content != null)
{
responseString = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
if (httpResponseMessage.IsSuccessStatusCode)
{
Succeed?.Invoke(responseString);
return;
}
Failed?.Invoke(httpResponseMessage.GetErrorType(),
$"{httpResponseMessage.ReasonPhrase}\n{responseString}");
}
//Catch all exceptions separately
catch(...){
}
finally
{
Dispose();
}
}
}
public class UserService(){
public CallbackObject<User> GetUser(){
var executor = new HttpExecutor(new RequestData());
//CallbackObject has also success and fail, and it hooks to executor events, deserializes string into object and sends model by his own events.
var callback = new CallbackObject<User>(executor);
executor.Execute();//in normal case called when all code has possibility to hook into event
return callback;
}
}
I feel that I should change method to:public async Task ExecuteAsync(){...} but then I would need take thread from thread pool by doing: Task.Run(()=>executor.ExecuteAsync());
It seems like it's a bit of fire and forget, but with callbacks (I await for response from network). How to handle this properly?
I'm refactoring old code which does synchronous http requests and returns Callback object with success and fail events. How to properly wrap code into async/await?
You get rid of the callbacks completely.
First, consider the failure case. (ErrorType, string) should be made into a custom Exception:
public sealed class ErrorTypeException : Exception
{
public ErrorType ErrorType { get; set; }
...
}
Then you can model Succeed / Failed callbacks as a single Task<string>:
public async Task<string> ExecuteAsync()
{
if (isExecuting) return;
isExecuting = true;
cancellationTokenSource = new CancellationTokenSource();
try
{
httpResponseMessage = await httpService.SendAsync(requestData, cancellationTokenSource.Token).ConfigureAwait(false);
var responseString = string.Empty;
if (httpResponseMessage.Content != null)
{
responseString = await httpResponseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
}
if (httpResponseMessage.IsSuccessStatusCode)
return responseString;
throw new ErrorTypeException(httpResponseMessage.GetErrorType(),
$"{httpResponseMessage.ReasonPhrase}\n{responseString}");
}
catch(...){
throw ...
}
finally
{
Dispose();
}
}
Usage:
public Task<User> GetUserAsync()
{
var executor = new HttpExecutor(new RequestData());
var text = await executor.ExecuteAsync();
return ParseUser(text);
}
My problem is the following:
On the UI thread I have a button event, from where I call a service method:
private async void RefreshObjectsButton_Click(object sender, EventArgs e)
{
var objectService = new ObjectService();
var objects = await objectService.GetObjects(UserInfo.Token);
}
The service method is:
public class ObjectService : ServiceClientBase, IObjectService
{
public async Task<ObservableCollection<ObjectViewModel>> GetObjects(string token)
{
var response = await GetAsync<ObservableCollection<HookViewModel>>("uri_address", token);
return response;
}
}
And the GetAsync method which is implemented in ServiceClientBase:
public async Task<T> GetAsync<T>(string uri, string token)
{
using (var client = CreateClient())
{
try
{
HttpResponseMessage response = new HttpResponseMessage();
response = await client.GetAsync(uri);
T retVal = default(T);
if (response.IsSuccessStatusCode)
{
retVal = await response.Content.ReadAsAsync<T>();
}
return retVal;
}
catch (Exception ex)
{
//TO DO log exception
return default(T);
}
}
}
When execution reaches GetAsync<T>(), the request is sent, I get a result and retVal contains a list of values. However after GetAsync<T>() execution ends, GetObjects() will not continue its execution anymore. I believe it's a deadlock as explained here. However using the advices seen in the previous link didn't resolve my issue. It's clearly I'm missing something here.
Can someone explain why is this deadlock happening, and maybe provide some further advice in resolving this issue?
I have a method that pulls some HTML via the HttpClient like so:
public static HttpClient web = new HttpClient();
public static async Task<string> GetHTMLDataAsync(string url)
{
string responseBodyAsText = "";
try
{
HttpResponseMessage response = await web.GetAsync(url);
response.EnsureSuccessStatusCode();
responseBodyAsText = await response.Content.ReadAsStringAsync();
}
catch (Exception e)
{
// Error handling
}
return responseBodyAsText;
}
I have another method that looks like so:
private void HtmlReadComplete(string data)
{
// do something with the data
}
I would like to be able to call GetHTMLDataAsync and then have it call HtmlReadComplete on the UI thread when the html has been read. I naively thought this could somehow be done with something that looks like
GetHTMLDataAsync(url).ContinueWith(HtmlReadComplete);
But, I can't get the syntax correct, nor am I even sure that's the appropriate way to handle it.
Thanks in advance!
public async void ProcessHTMLData(string url)
{
string HTMLData = await GetHTMLDataAsync(url);
HTMLReadComplete(HTMLData);
}
or even
public async void ProcessHTMLData(string url)
{
HTMLReadComplete(await GetHTMLDataAsync(url));
}
You're close, but ContinueWith() takes a delegate with Task as its parameter, so you can do:
GetHTMLDataAsync(url).ContinueWith(t => HtmlReadComplete(t.Result));
Normally, you should be careful with using Result together with async, because Result blocks if the Task hasn't finished yet. But in this case, you know for sure that the Task is complete, you Result won't block.