Class library making api call doesn't work in specific projects - c#

I've got a class library for talking to a logging api server, the method "chain" is this:
Entry point ->
private static bool SendChecksumToServer(Checksum checksum)
{
var res = _api.GetAsync($"Checksum?assemblyName={checksum.CurrentAssembly}&checkSum={checksum.LogFileChecksum}&fileName={checksum.FileName}");
return _api.Deserialize<bool>(res.Result.Content.ReadAsStringAsync().Result);
}
Which calls this:
public async Task<HttpResponseMessage> GetAsync(string apiCall)
{
ApiGet get = new ApiGet();
return await get.GetAsync(apiCall, client);
}
Which calls this:
public async Task<HttpResponseMessage> GetAsync(string apiCall, HttpClient client)
{
var response = await client.GetAsync(apiCall);
return response;
}
This works completely fine when I use the class library within a console app, but as soon as I move it to an actual application (MVC) it stops working, it doesn't even hit the controller action at all, I've tried everything I can think of like checking firewalls, making sure the async is correct (although I'm sure it still isn't because the api not responding freezes the app, but I can't bubble the async any higher)

Most likely experiencing a deadlock because of .Result blocking call.
Don’t mix blocking and async code
Reference Async/Await - Best Practices in Asynchronous Programming
Refactor the code to be async all the way
private static async Task<bool> SendChecksumToServer(Checksum checksum) {
var res = await _api.GetAsync($"Checksum?assemblyName={checksum.CurrentAssembly}&checkSum={checksum.LogFileChecksum}&fileName={checksum.FileName}");
String data = await res.Result.Content.ReadAsStringAsync();
return _api.Deserialize<bool>(data);
}
Ensure what ever is calling SendChecksumToServer also awaits the task,
and also not using async-await in the other calls if nothing needs to be awaited.
public Task<HttpResponseMessage> GetAsync(string apiCall) {
ApiGet get = new ApiGet();
return get.GetAsync(apiCall, client);
}
ApiGet
public Task<HttpResponseMessage> GetAsync(string apiCall, HttpClient client) {
return client.GetAsync(apiCall);
}

Related

How to execute different REST API requests in parallel in C# on .NET Core?

Problem Statement
I need to send multiple API calls at one shot.
I have three different API endpoints as shown below, and all these need to be called together almost as quickly as possible. It's all independent of each other.
public async Task<string> GetA(string a)
{
}
public async Task<string> GetB(int a)
{
}
public async Task<string> GetC(int a, string a)
{
}
What I tried
I was trying like this:
public async Task CallMultipleAPIs()
{
await GetA("");
await GetB(1);
await GetC(1, "");
}
How to implement parallelism here?
What you need is concurrency (not parallelism - i.e., multiple threads).
Concurrent asynchronous code is done by using Task.WhenAll:
public async Task CallMultipleAPIs()
{
var taskA = GetA("");
var taskB = GetB(1);
var taskC = GetC(1, "");
await Task.WhenAll(taskA, taskB, taskC);
}

Integrating async await into synchronous methods

I've been banging my head against a wall for two days now, and frankly I'm annoyed with myself because I just can't seem to get it.
I'm in a webapi context. During this request I need to send some data to one of our other systems, this system is slow to return, due to heavy calculations and multiple database saves etc etc. I need to log the result of this operation, regardless of whether it is successful or not. But I don't want to wait around for it to finish.
I've read that I should be async await all the way from top to bottom. I would have to convert numerous methods if I decided to do this, as I'm already 3 or 4 methods deep, which I fear would branch out even more.
What are my options here? If I go async await all the way down, what do I do with the methods higher up the stack, like my WebApi controllers?
Here is my code, I've tried to thin it down as much as I can. Right now I'm using Task.Result() in the method PushResult(). Which to my understanding is blocking the async? This code works in that the request gets sent. But the TestLog is always last, not first. Therefore not async.
//I'm in a public service and referenced twice
private void MyEndProcess()
{
// other stuff
_vendorPushService.PushResult(); // This could take a while and I have to wait for it!
_logService.PostLog(LogType.TestLog, "Test");
}
//I'm referenced above and somewhere else in the code base
public void PushResult()
{
ExternalResultModel externalResultModel = _resultService.GetExternalResultModel();
PushedResultModel pushedResult = new PushedResultModel();
try
{
pushedResult = _vendorRequestService.PushResultAsync(externalResultModel).Result;
}
catch (Exception ex)
{
pushedResult.Success = false;
}
if (pushedResult.Success)
{
_logService.PostLog(LogType.SuccessLog, pushedResult.Message);
}
else
{
_logService.PostLog(LogType.FailedLog, pushedResult.Message);
}
}
public async Task<PushedResultModel> PushResultAsync(ExternalResultModel externalResultModel)
{
// setup the requestMessage
HttpResponseMessage responseMessage = await _httpRequestService
.SendRequest(requestMessage)
.ConfigureAwait(false);
return new PushedResultModel
{
Success = responseMessage.IsSuccessStatusCode,
Message = await responseMessage.Content.ReadAsStringAsync()
};
}
public class HttpRequestService : IHttpRequestService
{
private readonly HttpClient _httpClient;
public HttpRequestService(IHttpClientAccessor httpClientAccessor)
{
_httpClient = httpClientAccessor.HttpClient;
}
public async Task<HttpResponseMessage> SendRequest(HttpRequestMessage requestMessage)
{
HttpResponseMessage httpResponseMessage = await _httpClient.SendAsync(requestMessage).ConfigureAwait(false);
return httpResponseMessage;
}
}
You should implement async await all the way from top to bottom.
If I go async await all the way down, what do I do with the methods higher up the stack, like my WebApi controllers?
Just make your controller actions async like this:
[RoutePrefix("api")]
public class PresidentsController : ApiController
{
[Route("presidents")]
public async Task<IHttpActionResult> GetPresidents()
{
await Task.Delay(TimeSpan.FromSeconds(10)).ConfigureAwait(false);
return Ok();
}
}
It's easiest way to implement async methods. Even if it will add some work to change everything to async it will benefit in future, because You will avoid many problem with async code.
If you absolutly HAVE to use async method in synchronous methods make it block in ONE place, like this:
public void MySyncMethod()
{
try
{
this.MyAsyncMethod().Wait();
}
catch (Exception exception)
{
//omited
}
}
private async Task MyAsyncMethod()
{
await AsyncLogic().ConfigureAwait(false);
}
But i don't recommend it. You should just use async await all the way to controller action.
In your comment you said you want to process a task in the background and not make the client calling your API wait. To do that, you don't really need to use async/await.
Try this:
private void MyEndProcess()
{
// other stuff
Task.Run(_vendorPushService.PushResult()).ConfigureAwait(false); //fire and forget
_logService.PostLog(LogType.TestLog, "Test");
}
The Task.Run will start the task, and the ConfigureAwait(false) tells it that it does not need to resume on the same context that we're currently on (meaning that the context can close before the task is finished - i.e. the response can be sent back without waiting for the task to finish).
You will get a compiler warning that you're not awaiting Task.Run, but that's what you want.
Keep in mind that when you do this, HttpContext.Current will not be available inside PushResult.

Hung returning Follows data from Relationships endpoint

I'm trying to return a list of followed users from the Instagram API. I'm on a sandbox account using the InstaSharp wrapper for .NET.
The action method is being called after user is authenticated.
public ActionResult Following()
{
var oAuthResponse = Session["InstaSharp.AuthInfo"] as OAuthResponse;
if (oAuthResponse == null)
{
return RedirectToAction("Login");
}
var info = new InstaSharp.Endpoints.Relationships(config_, oAuthResponse);
var following = info.Follows("10").Result;
return View(following.Data);
}
Try making the method async all the way through instead of making the blocking call .Result which runs the risk of causing a deadlock
public async Task<ActionResult> Following() {
var oAuthResponse = Session["InstaSharp.AuthInfo"] as OAuthResponse;
if (oAuthResponse == null) {
return RedirectToAction("Login");
}
var info = new InstaSharp.Endpoints.Relationships(config_, oAuthResponse);
var following = await info.Follows("10");
return View(following.Data);
}
depending on how info.Follows was implemented.
Looking at the Github repo, the API internally makes a call to a method defined like this
public static async Task<T> ExecuteAsync<T>(this HttpClient client, HttpRequestMessage request)
Which looks like your smoking gun as calling .Result higher up the call stack on this task would result in your experienced deadlock.
Reference Async/Await - Best Practices in Asynchronous Programming

How do I hide Task of Task?

Consider the following method:
private async Task<Task<Response>> SendAsync(string data)
{
this.Tcs = new TaskCompletionSource<Response>();
await this.Stream.WriteAsync(...);
await this.Stream.FlushAsync();
return this.Tcs.Task;
}
I have an async method, which I expect to return Task<Response>. But since I want to return TaskCompletionSource<Response> (which gets set elsewhere, so I can't await it here), I have to actually return Task<Task<Response>> instead.
In the calling code, I have two ways of dealing with it while hiding this ugliness from the outside of the class. Assuming the response is not important and can be ignored, I can simply return a Task:
public Task GetAsync(string key)
{
return this.SendAsync("GET " + key);
}
On the other hand, if I want the response, I have to use this ugly await await to make it work:
public async Task<Response> GetAsync(string key)
{
return await await this.SendAsync("GET " + key);
}
Is there a better way of dealing with this, i.e. returning the Task<Response> from SendAsync() without exposing a Task<Task<Response>> outside the class, and at the same time not using the await await?
I'm not sure why you need to use a TaskCompletionSource inside an async method. Usually you either do the one or the other.
But if you must then forget returning the TaskCompletionSource.Task. Simply await the task like you do the rest of the async methods (WriteAsync and FlushAsync) and change the method to return Task<Response>:
private async Task<Response> SendAsync(string data)
{
this.Tcs = new TaskCompletionSource<Response>();
await this.Stream.WriteAsync(...);
await this.Stream.FlushAsync();
return await this.Tcs.Task;
}
That way the async method returns a task that gets completed when there's a Response so you only need to await SendAsync("...") once.
The answer by #i3arnon is a good solution, however another solution is to use the Unwrap extension method.
The TaskExtensions.Unwrap method is designed for converting a Task<Task<TResult>> into a Task<TResult> and can be used as follows:
public Task<Response> GetAsync(string key)
{
return this.SendAsync("GET " + key).Unwrap();
}
Any result, exception or cancellation will be propagated correctly to the resulting Task<TResult>.

C# Tasks get result or catch exception

I have:
public static async Task<string> httpRequest(HttpWebRequest request)
I would like to do this:
string rez1;
static void test()
{
Task.Factory.StartNew(() => {
//How can I get result like rez1= httpRequest((HttpWebRequest)HttpWebRequest.Create("google.com")));
//or catch WebException here.
});
}
How can I do it?
Thanks
You have it mixed up a little bit. When your methods signature is:
public static async Task<string> httpRequest(HttpWebRequest request)
That means "this method is invoked asynchronously, i will call it and it will return imminently with a promise to finish in the future".
You should change your method to look like this:
Edit
Fixed the code according to the comments made.
public static Task<string> httpRequest(HttpWebRequest request)
{
return Task.Factory.Startnew(() = > {
return HttpWebRequest.Create("google.com")
}
}
When your method is marked as async, that means the caller might think it is "pure" async, which means no threads execute behind the scenes. If you do fire up a new thread (as you are doing here, by using a Thread Pool thread) you should explicitly comment your method and tell your invoker that he will be firing up a new thread.
You can save yourself firing up a new Task if you're using .NET 4.5 and have access to the new HttpClient class.
You can change your method to look like this:
public static async Task<string> httpRequest(HttpWebRequest request)
{
var httpClient = new HttpClient();
var response = await httpClient.GetAsync("http://www.google.com")
var stringResult = await response.Content.ReadAsStringAsync();
return stringResult;
}

Categories