Parallel Invoke with AwaitAsync in WebApi blocking - c#

I've a webApi operation which executes 2 operations in || which internally invokes HttpClient sendAsync. If I apply debuggers and execute call, it works and returns. If I remove debuggers, both the async calls still work (checked in Fiddler) but caller of WebApi operation doesn't gets any response (using AdvanceRest chrome plugin). From the other threads, possibly I'm not using async/await correctly and related to ASP.NET synchronizationContext
//**WEB API Controller***
class SomeController
{
public HttpResponseMessage Get()
{
Client someClient = new Client();
aResponse = new aResponse();
bResponse = new bResponse();
Parallel.Invoke(
() => {aResponse = someClient.a()},
() => {bResponse = someClient.b()});
var response = {a=aResponse, b=bResponse};
return Response.Create(OK, response}
}
class SomeClient
{
AResponse a()
{
var clientResponse = ClientMgr.Execute("url");
return new AResponse {HttpClientResponse = clientResponse.Result}
}
BResponse b()
{
var clientResponse = ClientMgr.Execute("url");
return new BResponse {HttpClientResponse = clientResponse.Result}
}
}
//Utility CLASS
public class ClientMgr
{
public static async Task<HttpResponseMessage> Execute(string url)
{
request = new HttpRequestMessage();
//....request fill
HttpClient client = new HttpClient();
var response = await client.SendAsync(request);
client.dispose();
return response;
}
}
public class AResponse
{
HttpResponseMessage HttpClientResponse {get;set;}
// Some other properties....
}
Why does operation returns response when I'm using breakpoints but as I soon as I remove them, it doesn't returns response?

Your problem (other than the fact that the code you posted doesn't compile) is that while you debug, the async operations actually complete. When you don't debug, they don't, and it returns a Task<YourResponse>, not the actual result of the Task.
In order for this to work, mark your method as async and use Task.WhenAll to asynchronously wait on both tasks:
[HttpGet]
public async Task<HttpResponseMessage> GetAsync()
{
Client someClient = new Client();
var aTask = someClient.AAsync();
var bTask = someClient.BAsync();
await Task.WhenAll(aTask, bTask);
var response = { a = aTask.Result, b = bTask.Result };
return Response.Create(OK, response}
}
Side note - You don't need to use Paralle.Invoke when you have IO bound operations. Those are redundant threads which will be blocked waiting for the IO's completion.

Related

HttpClient in async/sync implementation returns WaitingForActivation

I'm having a problem with async to sync implementation of HttpClient.
Id = 8, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
I know what I'm doing is probably a bad practice and it would be ideal to make all the path async, but that's a request that the company is making me, so I have to do like this.
Project is build in NET Standard 1.1, to be used as a NuGet package and to be compatible with Framework and Core as well.
Here's my main client construction...
private static HttpClient _client;
private static Uri _baseAddress;
private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings
{ DefaultValueHandling = DefaultValueHandling.Ignore, NullValueHandling = NullValueHandling.Ignore, MissingMemberHandling = MissingMemberHandling.Ignore };
public Client() { }
private Client(string baseUrl, Config config)
{
_baseAddress = new Uri(baseUrl);
_client = new HttpClient { Timeout = TimeSpan.FromSeconds(config.Timeout) };
_client.DefaultRequestHeaders.Accept.Clear();
_client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
_client.DefaultRequestHeaders.Add("X-API-KEY", config.Token);
}
private Client _paymentClient;
private Client _mainClient;
public Client Create(bool payment, Config config = null)
{
if (!payment)
{
_mainClient = _mainClient ?? new Client("https://api.address.com/", config);
return _mainClient;
}
_paymentClient = _paymentClient ?? new Client("https://payment.address.com/", config);
return _paymentClient;
}
public void Dispose() => _client.Dispose();
private static async Task<T> Send<T>(HttpMethod method, string url, object data = null)
{
var uri = new UriBuilder(_baseAddress);
uri.Path += url;
var request = new HttpRequestMessage(method, uri.Uri);
if (data != null)
request.Content = new StringContent(JsonConvert.SerializeObject(data, _settings), Encoding.UTF8, "application/json");
var response = await _client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
T result = default;
if (response.IsSuccessStatusCode)
{
if (response.Content.Headers.ContentType.MediaType == "application/json")
{
var responseObj = JsonConvert.DeserializeObject<Response<T>>(content, _settings);
if (responseObj.HasError)
throw new Safe2PayException(responseObj.ErrorCode, responseObj.Error);
responseObj.ResponseDetail = result;
}
}
else throw new Exception((int) response.StatusCode + "-" + response.StatusCode);
request.Dispose();
response.Dispose();
return result;
}
And the Send<T> method is supposed to be a general treatment to process the request and response, wrapped on generic calls like this:
internal Task<T> Get<T>(string url) => Send<T>(HttpMethod.Get, url);
//OR even async...
internal async Task<T> Get<T>(string url) => await Send<T>(HttpMethod.Get, url);
Which are called like this, to send and receive data..
private Client Client { get; }
public CheckoutRequest(Config config) => Client = new Client().Create(true, config);
public object Credit(Transaction transaction)
{
var response = Client.Post<Transaction>("v2/Payment", transaction);
return response;
}
My problem is that the client is always getting me a WaitingfForActivation or even Running or WaitingToRun, doesn't matter if I change it to...
Task.Run(() => Send<T>(HttpMethod.Get, url));
//or
Task.Run(() => Send<T>(HttpMethod.Get, url).Result);
//or
Task.Run(async () => await Send<T>(HttpMethod.Get, url));
//or
Task.Run(async () => await Send<T>(HttpMethod.Get, url).ConfigureAwait(false));
I've been trying to find what I'm doing wrong, tried to change all the awaits, but I'm not being sucessful with this, so any help will be very much appreciated.
I suspect your problem is here:
public object Credit(Transaction transaction)
{
var response = Client.Post<Transaction>("v2/Payment", transaction);
return response;
}
You didn't show your code for Post<T>(), but I assume it's also an async Task<T> method, which means response is a Task<T> and your code is basically doing this:
Start a task.
Return a description of the incomplete task.
When I assume this is really what you want:
Start the task.
Wait for the task to complete.
Return the result of the task.
Ideally, this should be an async method, and you can await the task:
public async Task<object> Credit(Transaction transaction)
{
var response = await Client.Post<Transaction>("v2/Payment", transaction);
return response;
}
If you absolutely must wait for the task synchronously (there are very few reasons to need to) then you can use .GetAwaiter().GetResult():
public object Credit(Transaction transaction)
{
var response = Client.Post<Transaction>("v2/Payment", transaction).GetAwaiter().GetResult();
return response;
}
The main benefit of .GetAwaiter().GetResult() instead of .Result is that, in the case of exceptions, it will throw the actual exception instead of an AggregateException.
Also, you can make your Create() method static:
public static Client Create(bool payment, Config config = null)
Then you don't need to initialize the class just to call it:
public CheckoutRequest(Config config) => Client = Client.Create(true, config);
Update: If you want async and non-async versions of the same method, you can follow the same standard that Microsoft uses and name the async method with the Async suffix. The non-async version can just call the async version. For example:
public async Task<object> CreditAsync(Transaction transaction)
{
var response = await Client.Post<Transaction>("v2/Payment", transaction);
return response;
}
public object Credit(Transaction transaction)
{
return CreditAsync(transaction).GetAwaiter().GetResult();
}

Struggling to get async working on deployment in ASP.net

The code works fine on my development environment, but in deployment with scallable architecture it appears to deadlock.
Objective here is to take a queue of API requests to send to SendGrid, batch them up and process each batch one at a time.
First call from ASHX handler
public void ProcessRequest(HttpContext context)
{
var result = Code.Helpers.Email.Sendgrid.Queue.Process().Result;
if (result.Success)
{
Queue.Process()
public static async Task<GenericMethodResult> Process()
{
var queueItems = GetQueueItemsToProcess();
var batches = BatchQueueItems(queueItems);
foreach (var batch in batches)
{
var r = await batch.SendToSendGrid();
if (r.StopBatch)
{
break;
}
}
return new GenericMethodResult(true);
}
SendToSendGrid()
public async Task<SendGridAPIMethodResponse> SendToSendGrid()
{
var r = new SendGridAPIMethodResponse();
var json = API.Functions.CreateJSONData(this);
var sg = new SendGridClient(Settings.Email.SendgridAPIKey);
dynamic response;
if (Action == Action.UpdateRecipient)
{
response = await sg.RequestAsync(SendGridClient.Method.PATCH, urlPath: "contactdb/recipients", requestBody: json);
}
string jsonResponse = response.Body.ReadAsStringAsync().Result;
// Process response...
return r;
}
I've stripped out as much of the code as I could.
Is anyone able to tell me why this code is timing out in production?
This blocking call to .Result in SendToSendGrid() is causing a deadlock as you are mixing async and blocking calls.
string jsonResponse = response.Body.ReadAsStringAsync().Result;
Use async all the way through
var jsonResponse = await response.Body.ReadAsStringAsync();
and try to avoid mixing blocking calls in async methods.
You should also conside making your handler async as well by using HttpTaskAsyncHandler.
public class MyHandler : HttpTaskAsyncHandler {
public override async Task ProcessRequestAsync(HttpContext context) {
var result = await Code.Helpers.Email.Sendgrid.Queue.Process();
if (result.Success) {
//..other code
}
}
}

ObjectDisposedException when trying to access Thread.CurrentPrincipal with async method

I'm fairly new to the new async/await stuff. However, I have the following classes:
public abstract class PluginBase
{
//Using EF to store log info to database
private EFContext _context = new EFContext();
private int Id = 1;
protected void LogEvent(string event, string details)
{
_context.LogEvents.Add(new LogItem(){
PluginId = this.Id,
Event = event,
Details = details,
User = Thread.CurrentPrincipal.Identity.Name
});
}
}
public class Plugin : PluginBase
{
public void Process()
{
CallWebService();
}
public async void CallWebService()
{
using(var http = new HttpClient())
{
...
var result = await http.PostAsync(memberURI, new StringContent(content, Encoding.UTF8,"application/json"));
if(result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
So, the idea is that Plugin.Process gets called. It in turn calls CallWebService(). CallWebService makes an asynchronous call to http.PostAsync. When I return from that call and try to call base.LogEvent(), I get an ObjectDisposedException stating that "Safe Handle has been Closed".
I know there is something going on where when the awaitable finishes, the rest of the code of the method has to be run. Maybe its being run in some other thread or context? If this is the case, how do I get the current user at the time of writing to the log?
Thanks for your help with this.
Edit
Based on the answer from Yuval, I made the following changes and it seems to work fine.
public void Process()
{
var task = CallWebService();
task.Wait();
}
public async Task CallWebService(List<Member> members)
{
using(var http = new HttpClient())
{
...
using(var result = await http.PostAsync(memberURI, new StringContent content, Encoding.UTF8, "application/json")))
{
if(result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
}
When I return from that call and try to call base.LogEvent(), I get an
ObjectDisposedException stating that "Safe Handle has been Closed".
That's because somewhere higher up the call-chain, someone is disposing your plugin object, which hasn't really finished the asynchronous operation. Using async void is doing a "fire and forget" operation. You don't actually await on Process, hence anyone calling it assumes it finished and disposes of your object.
Change your async void method to async Task, and await it:
public Task ProcessAsync()
{
return CallWebServiceAsync();
}
public async Task CallWebServiceAsync()
{
using (var http = new HttpClient())
{
var result = await http.PostAsync(memberURI,
new StringContent(content,
Encoding.UTF8,
"application/json"));
if (result.IsSuccessStatusCode)
_status = "Success";
else
_status = "Fail";
LogEvent("Service Call - " + _status,...);
}
}
Note you will need to await ProcessAsync somewhere higher up the call-stack as well.

ReactiveUI 6 Async Command Not Running on Background Thread in WPF app

ViewModel
public class MyViewModel:ReactiveObject, IRoutableViewModel{
private ReactiveList<string> _appExtensions;
public MyViewModel(IScreen screen){
HostScreen = screen;
AppExtensions = new ReactiveList<string>();
GetApplicationExtensions =
ReactiveCommand.CreateAsyncTask(x => _schemaService.GetApplicationExtensions()); // returns a Task<IEnumerable<string>>
GetApplicationExtensions
.ObserveOn(RxApp.MainThreadScheduler)
.SubscribeOn(RxApp.TaskpoolScheduler)
.Subscribe(p =>
{
using (_appExtensions.SuppressChangeNotifications())
{
_appExtensions.Clear();
_appExtensions.AddRange(p);
}
});
GetApplicationExtensions.ThrownExceptions.Subscribe(
ex => Console.WriteLine("Error during fetching of application extensions! Err: {0}", ex.Message));
}
// bound to a ListBox
public ReactiveList<string> AppExtensions
{
get { return _appExtensions; }
set { this.RaiseAndSetIfChanged(ref _appExtensions, value); }
}
public ReactiveCommand<IEnumerable<string>> GetApplicationExtensions { get; protected set; }
}
and the View has a <Button Command="{Binding GetApplicationExtensions}"></Button>.
implentation of GetApplicationExtensions
public async Task<IEnumerable<string>> GetApplicationExtensions()
{
IEnumerable<string> extensions = null;
using (var client = new HttpClient())
{
client.BaseAddress = BaseAddress;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var response = await client.GetAsync("applications");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
extensions = JsonConvert.DeserializeObject<IEnumerable<string>>(json);
}
}
return extensions;
}
From everything I've read about ReactiveUI and all the examples I've seen (althought there are extremely few for the new 6.0+ versions), this should make my async call (which makes an async HTTP request via HttpClient) run on a background thread and update a ListBox in my view when the results are returned from it. However, this is not the case - the UI gets locked up for the duration of the async call. What am I doing wrong?
UPDATE
If I wrapped my HTTP call in a Task then everything worked as intended - the UI did not hang up at all. So the new implementation of my service call is this:
public Task<IEnumerable<string>> GetApplicationExtensions()
{
var extensionsTask = Task.Factory.StartNew(async () =>
{
IEnumerable<string> extensions = null;
using (var client = new HttpClient())
{
client.BaseAddress = BaseAddress;
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
var response = await client.GetAsync("applications");
if (response.IsSuccessStatusCode)
{
var json = await response.Content.ReadAsStringAsync();
extensions = JsonConvert.DeserializeObject<IEnumerable<string>>(json);
}
}
return extensions;
}
return extensionsTask.Result;
}
Also, with this change to my async service call, I could remove the ObserveOn and SubscribeOn from my ReactiveCommand like #PaulBetts suggessted. So my ReactiveCommand implementation in my view model's constructor became this:
GetApplicationExtensions =
ReactiveCommand.CreateAsyncTask(x => _schemaService.GetApplicationExtensions()); // returns a Task<IEnumerable<string>>
GetApplicationExtensions
.Subscribe(p =>
{
using (_appExtensions.SuppressChangeNotifications())
{
_appExtensions.Clear();
_appExtensions.AddRange(p);
}
});
Can you show the implementation of _schemaService.GetApplicationExtensions()?
Depending on how it is implemented it might not actually be on another thread. Arguably, ReactiveCommand should guarantee that even async operations that accidentally burn CPU before running an async op are forced onto background threads, but efficiency is trumping defensive programming in this case.
You shouldn't need either SubscribeOn or ObserveOn, ReactiveCommand already guarantees that values will be returned on the UI thread. Otherwise, this code is looking good!
Change
GetApplicationExtensions
.ObserveOn(RxApp.MainThreadScheduler)
.SubscribeOn(RxApp.TaskpoolScheduler)
to
GetApplicationExtensions
.SubscribeOn(RxApp.TaskpoolScheduler)
.ObserveOn(RxApp.MainThreadScheduler)
ObserveOn should be after SubscribeOn

Async is becoming a pain in the behind because I'm trying to make a re-usable library that doesn't suck

Because Post requests to APIs need to run asynchronously on windows phone, I am struggling to create a lean easy to use library to interact with an API.
The issue is that people using the library will always need to supply a callback function.
Let's take a look at some pseudo code:
PostRequest Class to help me with POST requests:
class PostRequest
{
private Action<MemoryStream> Callback;
public PostRequest(string urlPath, string data, Action<MemoryStream> callback)
{
Callback = callback;
// Form the URI
UriBuilder fullUri = new UriBuilder(urlPath);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
// Initialize a new WebRequest
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(fullUri.Uri);
request.Method = "POST";
// Set up the state object for the async request
DataUpdateState dataState = new DataUpdateState();
dataState.AsyncRequest = request;
// Start the asynchronous request
request.BeginGetResponse(new AsyncCallback(HandleResponse),
dataState);
}
private void HandleResponse(IAsyncResult asyncResult)
{
// Get the state information
DataUpdateState dataState = (DataUpdateState)asyncResult.AsyncState;
HttpWebRequest dataRequest = (HttpWebRequest)dataState.AsyncRequest;
// End the async request
dataState.AsyncResponse = (HttpWebResponse)dataRequest.EndGetResponse(asyncResult);
if (dataState.AsyncResponse.StatusCode.ToString() == "OK")
{
// Create a stream from the response
Stream response = dataState.AsyncResponse.GetResponseStream();
TextReader textReader = new StreamReader(response, true);
string jsonString = textReader.ReadToEnd();
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
// Send the stream through to the callback function
Callback(stream);
}
}
}
public class DataUpdateState
{
public HttpWebRequest AsyncRequest { get; set; }
public HttpWebResponse AsyncResponse { get; set; }
}
The API Access Object classes:
class APIAuthenticationCredentials
{
public String Username { get; set; }
public String Password { get; set; }
}
class APIAO
{
private String AuthUrl = "http://api.example.com/";
public static Auth Auth = new Auth();
//...
public static void Authenticate( String data, APIAuthenticationCredentials credentials, Action<MemoryStream> callback )
{
PostRequest request = new PostRequest(AuthURL, data, callback);
}
//...
}
You will notice I have to pass a callback function all the way through this so that once the data is returned by the HandleResponse method in my PostRequest class, the data is forwarded onto some controller that makes the screen do something with the data. At the moment, it's not ultra horrid to use:
private void DisplayData(MemoryStream stream)
{
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Auth));
APIAO.Auth = (Auth)serializer.ReadObject(stream);
}
//...
APIAuthenticationCredentials credentials = new APIAuthenticationCredentials {
Username = "whatever",
Password = "whatever"
}
APIAO.Authenticate( credentials, DisplayData );
//...
The problem is I want to create some kind of repository style pattern... Let's say the API returned different json models, one call returned an array of products... the problem is that I want to create one lovely repository call eg:
IProductRepository productRepository = new ProductRepository();
productRepository.GetAll();
But I've gotta put some GOSH DARN callback function in it too and that means every repository method of any object type returned by the API is going to have this MemoryStream callback... and if I ever want to change that functionality, I've gotta update that stuff everywhere yo. :(
Has anyone seen a better way of doing this crap.
This is starting to become far too complex
--crying
A simpler answer using newer language constructs would be:
public static Task<string> GetData(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
return client.DownloadStringTaskAsync(fullUri.Uri);
}
In a 4.0 project you can use a TaskCompletionSource to translate a non-Task asynchronous model into a Task:
public static Task<string> GetData2(string url, string data)
{
UriBuilder fullUri = new UriBuilder(url);
if (!string.IsNullOrEmpty(data))
fullUri.Query = data;
WebClient client = new WebClient();
client.Credentials = CredentialCache.DefaultCredentials;//TODO update as needed
var tcs = new TaskCompletionSource<string>();
client.DownloadStringCompleted += (s, args) =>
{
if (args.Error != null)
tcs.TrySetException(args.Error);
else if (args.Cancelled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(args.Result);
};
client.DownloadStringAsync(fullUri.Uri);
return tcs.Task;
}
The caller now has a Task<string> that represents the results of this asynchronous operation. They can wait on it synchronously and get the result using the Result property, they can add a callback that will execute when the operation finishes using ContinueWith, or they can await the task in an async method which, under the hood, will wire up the remainder of that method as a continuation of that task, but without creating a new method or even a new scope, i.e.
public static async Task Foo()
{
string result = await GetData("http://google.com", "");
Console.WriteLine(result);
}
This will start the asynchronous task, add a callback (or continuation) to that task so that when it runs it will continue executing code where it left off, at which point it will then write the results to the console and mark the Task that this method returns as completed, so that any continuations to this method will then execute (allowing for composition of async methods).

Categories

Resources