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?
Related
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);
}
I am trying to call an async method from a synchronous method and it keeps bombing on the call to GetUsTraceApiHealth() but with no errors. What is the problem?
Calling Method:
public ActionResult TestSSN()
{
try
{
var apiResponse = GetUsTraceApiHealth().GetAwaiter().GetResult();
string responseBody = apiResponse.Content.ReadAsStringAsync().Result;
return Json(responseBody, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
Method Being Called:
public async Task<HttpResponseMessage> GetUsTraceApiHealth()
{
using (HttpClient httpClient = new HttpClient())
{
try
{
string uri = $"https://trace.{ConfigHelper.SterlingDomain}health?deep";
HttpResponseMessage apiResponse = await httpClient.GetAsync(uri);
return apiResponse;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
}
Follow the async mantra of "async all the way down". Basically, you should almost never call .Result on a task. In the majority of cases, your calling method should also be async. Then you can simply await the result of the operation:
public async Task<ActionResult> TestSSN()
{
//...
var apiResponse = await GetUsTraceApiHealth();
string responseBody = await apiResponse.Content.ReadAsStringAsync();
//...
}
It should be up to the application host at the top level (in this case ASP.NET and the web server) to handle the synchronization context. You shouldn't try to mask an asynchronous operation as a synchronous one.
Simplified version of your code:
public async Task<ActionResult> TestSSN()
{
var apiResponse = await GetUsTraceApiHealthAsync();
return Json(apiResponse, JsonRequestBehavior.AllowGet);
}
public async Task<string> GetUsTraceApiHealthAsync()
{
using (HttpClient httpClient = new HttpClient())
{
string uri = $"https://trace.{ConfigHelper.SterlingDomain}health?deep";
return apiResponse = await httpClient.GetStringAsync(uri);
}
}
There's no reason to return the HttpResponseMessage to read its content as string, just use GetStringAsync.
Also, never catch an exception just to rethrow it. If you need to do that, use:
catch(Exception ex)
{
//log or whatever
throw;
}
You shouldn't mix the async and sync operations together. Proper way to perform it is decorating your methods as async and simply using await;
public async Task<ActionResult> TestSSN()
{
try
{
var apiResponse = await GetUsTraceApiHealth().GetAwaiter().GetResult();
string responseBody = await apiResponse.Content.ReadAsStringAsync().Result;
return Json(responseBody, JsonRequestBehavior.AllowGet);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
If you don't able to apply async in the all paths, you could use ConfigureAwait to prevent deadlock.
public async Task<HttpResponseMessage> GetUsTraceApiHealth()
{
using (HttpClient httpClient = new HttpClient())
{
try
{
string uri = $"https://trace.{ConfigHelper.SterlingDomain}health?deep";
HttpResponseMessage apiResponse = await httpClient.GetAsync(uri).ConfigureAwait(false);
return apiResponse;
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
}
I am not familiar with threading in .NET.
I have an ansync method MyTest:
public async Task MyTest() {
using (HttpClient httpClient = new HttpClient()) {
httpClient.BaseAddress = new Uri(_uri);
var response = await httpClient.GetAsync("API/GetData");
if(response!=null && response.IsSuccessStatusCode) {
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
}
}
The problem that I am running into is calling the method to get the results (Dictionary).
When I step though my code I am seeing the IsCompleted is done before the results come back from my rest call.
How do I properly use threading in this case?
My method to call the async method.
public void GetTestData()
{
try
{
ARestService rest = new ARestService();
Task tsk = new Task(rest.MyTest);
if (tsk.IsCompleted)
{
var tst = "Done?";
}
}
catch(Exception ex)
{
string a = ex.Message;
}
}
If you can turn your GetTestData method into an async method simply do this.
public async Task GetTestData()
{
try
{
ARestService rest = new ARestService();
await rest.MyTest();
var tst = "Done?";
}
catch(Exception ex)
{
string a = ex.Message;
}
}
You should also define that your method returns a Task<Dictionary<string, string>> to receive the result of your rest service call, with the following statement.
Dictionary<string, string> dict = await rest.MyTest();
If not, have a look at some workarounds, like using GetAwaiter().GetResult() but as explained in this question Is .GetAwaiter().GetResult(); safe for general use? it can cause some problems, so the best option is to make your calling code async too.
I'm working on an async http call using HttpClient. The call is made inside an async task. The call is successful and I get a response from the Http call. But when I try to return the response from the task nothing happens, even though I have a breakpoint waiting after the return.
public void ExecuteTask(Foundation.Security.SecurityToken token, Order order)
{
ExecuteTaskAsync(token, order).Wait();
}
public async Task ExecuteTaskAsync(Foundation.Security.SecurityToken token, Order order)
{
if (order != null)
{
log.Info("Starting export of order " + order.ID.ToString());
bool success = await ExportOrder(order, token);
if (!success)
{
log.Error("Failed to export order with ID " + order.ID.ToString());
}
}
}
private async Task<bool> ExportOrder(Order order, Foundation.Security.SecurityToken token)
{
try
{
ResponseObject response = await webService.SendOrder(new SenderInformation(token), new ReceiverInformation(order, token));
if (response.Success && response.Status.Equals("201", StringComparison.OrdinalIgnoreCase))
{
log.Info(String.Format("Order ({0}) was successfully exported"), order.ExternalOrderID);
return true;
}
return false;
}
catch (Exception e)
{
log.Error(String.Format("Exception occured while exporting order ({0})", order.ID), e);
return false;
}
}
Below is the code which does the actual http call. I marked the last functional line with the comment "The code successfully reach this line. After this nothing happens"
public Task<ResponseObject> SendOrder(SenderInformation sender, ReceiverInformation receiver)
{
OrderRequest request = new OrderRequest(sender, receiver);
return ExecuteRequest<OrderRequest, ResponseObject>(request);
}
private async Task<ResponseType> ExecuteRequest<RequestType, ResponseType> (RequestType request)
where RequestType : RequestObject
where ResponseType : class, ResponseObject, new()
{
try
{
using (var client = new HttpClient())
{
string xml = SerializeRequest(request);
HttpContent content = new StringContent(xml);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("text/xml");
string requestUrl = "URL";
HttpResponseMessage response = await client.PostAsync(requestUrl, content).ConfigureAwait(false);
// Parse response
if (response.IsSuccessStatusCode)
{
Stream responseStream = await response.Content.ReadAsStreamAsync();
ResponseType responseObject = DeserializeResponse<ResponseType>(responseStream);
if (responseObject != null)
{
responseObject.Success = true;
return responseObject; //The code successfully reach this line. After this nothing happens
}
else
{
log.Error("Response could not be deserialized");
}
}
else
{
log.Error("Error during request, got status code " + response.StatusCode);
}
}
}
catch (Exception e)
{
log.Error("Something went wrong!", e);
}
return new ResponseType() { Success = false };
}
The problem is on this line:
ExecuteTaskAsync(token, order).Wait();
This causes a deadlock: the awaits in the called method can't resume because the UI thread is blocked.
When you use async code, you must use it all the way; never wait synchronously for an async task to complete.