Creating a lambda expression for a task<string> - c#

How would I create a lambda expression for a task that returns a string?
This is what I have tried but I get an error.
Thank you for any help.
public static async Task<string> GetStringAsync(string path)
{
try
{
var task = new Task<string>(async () =>
{
var response = await Client.GetAsync(path);
var responsestring = await response.Content.ReadAsStringAsync();
return responsestring;
});
return await Task.WhenAny(task, Task.Delay(20000)) == task
? task.Result
: RequestTimeOutMessage;
}
catch (Exception e)
{
return e.GetBaseException().Message;
}
}
}

You should never use the Task constructor. There are literally no good reasons to use it.
Your problem can be naturally expressed as a separate method:
public static async Task<string> GetStringAsync(string path)
{
try
{
var task = DoGetStringAsync(path);
return await Task.WhenAny(task, Task.Delay(20000)) == task
? await task
: RequestTimeOutMessage;
}
catch (Exception e)
{
return e.GetBaseException().Message;
}
}
private async Task<string> DoGetStringAsync(string path)
{
var response = await Client.GetAsync(path);
var responsestring = await response.Content.ReadAsStringAsync();
return responsestring;
}
If you really want an async lambda expression (personally, I think it obfuscates the code unnecessarily), you can move the separate method inline and assign it to an asynchronous delegate type:
public static async Task<string> GetStringAsync(string path)
{
try
{
Func<Task<string>> func = () =>
{
var response = await Client.GetAsync(path);
var responsestring = await response.Content.ReadAsStringAsync();
return responsestring;
};
var task = func();
return await Task.WhenAny(task, Task.Delay(20000)) == task
? await task
: RequestTimeOutMessage;
}
catch (Exception e)
{
return e.GetBaseException().Message;
}
}
On a side note, I recommend using exceptions for timeouts as well as communication errors, rather than special strings.

This is the "simplest" way I'm aware of:
//Without result
var task = ((Func<Task>)(async () =>{
await Task.Delay(100);
}))();
//With result
var task2 = ((Func<Task<string>>)(async () =>{
await Task.Delay(100);
return "your-string";
}))();

Related

C# async lock get the same result without code execution

I have a method that returns some value based on an API call, this API limits the amount of calls that you can do per period of time. I need to access the results of this call from multiple threads. Right now i have the following code:
class ReturningSemaphoreLocker<TOutput>
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public async Task<T> LockAsync<T>(Func<Task<T>> worker)
{
await _semaphore.WaitAsync();
try
{
return await worker();
}
finally
{
_semaphore.Release();
}
}
}
Usage example:
...
private static readonly ReturningSemaphoreLocker<List<int>> LockingSemaphore = new ReturningSemaphoreLocker<List<int>>();
...
public async Task<List<int>> GetStuff()
{
return await LockingSemaphore.LockAsync(async () =>
{
var client = _clientFactory.CreateClient("SomeName");
using (var cts = GetDefaultRequestCts())
{
var resp = await client.GetAsync("API TO QUERY URL", cts.Token);
var jsonString = await resp.Content.ReadAsStringAsync();
var items = JsonConvert.DeserializeObject<List<int>>(jsonString);
return items;
}
});
}
So the question is: how do i get the same result from GetStuff() if it's already running WITHOUT querying the API again and query the API again if the method is not running at this very moment?
The trick here is to hold onto the Task<T> that is the incomplete result; consider the following completely untested approach - the _inProgress field is the key here:
private static readonly ReturningSemaphoreLocker<List<int>> LockingSemaphore = new ReturningSemaphoreLocker<List<int>>();
...
private Task<List<int>> _inProgress;
public Task<List<int>> GetStuffAsync()
{
if (_inProgress != null) return _inProgress;
return _inProgress = GetStuffImplAsync();
}
private async Task<List<int>> GetStuffImplAsync()
{
var result = await LockingSemaphore.LockAsync(async () =>
{
var client = _clientFactory.CreateClient("SomeName");
using (var cts = GetDefaultRequestCts())
{
var resp = await client.GetAsync("API TO QUERY URL", cts.Token);
var jsonString = await resp.Content.ReadAsStringAsync();
var items = JsonConvert.DeserializeObject<List<int>>(jsonString);
return items;
}
});
// this is important so that if everything turns
// out to be synchronous, we don't nuke the _inProgress field *before*
// it has actually been set
await Task.Yield();
// and now wipe the field since we know it is no longer in progress;
// the next caller should actually try to do something interesting
_inProgress = null;
return result;
}
Here is a class that you could use for time-based throttling, instead of the ReturningSemaphoreLocker:
class ThrottledOperation
{
private readonly object _locker = new object();
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
private Task _task;
public Task<T> GetValueAsync<T>(Func<Task<T>> taskFactory, TimeSpan interval)
{
lock (_locker)
{
if (_task != null && (_stopwatch.Elapsed < interval || !_task.IsCompleted))
{
return (Task<T>)_task;
}
_task = taskFactory();
_stopwatch.Restart();
return (Task<T>)_task;
}
}
}
The GetValueAsync method returns the same task, until the throttling interval has been elapsed and the task has been completed. At that point it creates and returns a new task, using the supplied task-factory method.
Usage example:
private static readonly ThrottledOperation _throttledStuff = new ThrottledOperation();
public Task<List<int>> GetStuffAsync()
{
return _throttledStuff.GetValueAsync(async () =>
{
var client = _clientFactory.CreateClient("SomeName");
using (var cts = GetDefaultRequestCts())
{
var resp = await client.GetAsync("API TO QUERY URL", cts.Token);
var jsonString = await resp.Content.ReadAsStringAsync();
var items = JsonConvert.DeserializeObject<List<int>>(jsonString);
return items;
}
}, TimeSpan.FromSeconds(30));
}

Set a timeout on a redirect chain

I am trying to trace a chain of redirects (for an online ad pixel) programmatically, but with a timeout of 2 seconds (in other words, if the redirect chain takes more than 2 seconds to resolve, I want it to abort and return null).
My code is (more or less) running synchronously, so I had to do some acrobatics to do what I wanted, but functionally speaking, it seems to work... except for the timeout part.
I have some asynchronous helpers like so:
public static async Task<TResult> TimeoutAfter<TResult>(this Task<TResult> task, TimeSpan timeout)
{
using (var timeoutCancellationTokenSource = new CancellationTokenSource())
{
var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token));
if (completedTask != task)
{
throw new TimeoutException();
}
timeoutCancellationTokenSource.Cancel();
return await task;
}
}
public static T ToSynchronousResult<T>(this Task<T> task)
{
return Task.Run(async () => await task).Result;
}
The TimeoutAfter() helper method was adapted from the SO article that can be found here. In my service I have a method that resembles this:
public string GetFinalUrl(string url)
{
string finalUrl;
try
{
finalUrl = FollowDestinationUrl(url).TimeoutAfter(TimeSpan.FromSeconds(2)).ToSynchronousResult();
}
catch (TimeoutException)
{
finalUrl = null;
}
return finalUrl;
}
private async Task<string> FollowDestinationUrl(string url)
{
var request = _webRequestFactory.CreateGet(url);
var payload = await request.GetResponseAsync();
return payload.ResponseUri.ToString();
}
The _webRequestFactory here returns an HttpWebRequest abstraction that was written as an IHttpRequest.
In my success case unit test (response under 2 seconds), I get back the result I expect:
private class TestWebResponse : WebResponse
{
public override Uri ResponseUri => new Uri("https://www.mytest.com/responseIsGood");
}
[TestMethod]
public void RedirectUriUnderTimeout()
{
//arrange
var service = GetService();
A.CallTo(() => _httpRequest.GetResponseAsync()).ReturnsLazily(() => new TestWebResponse());
A.CallTo(() => _httpRequest.GetResponseString())
.ReturnsLazily(() => VALID_REQUEST_PAYLOAD);
//act
var url = service.GetFinalUrl("https://someplace.com/testurl");
//assert
Assert.IsNotNull(url);
}
...however, when I try to implement a delay to verify the timeout is working correctly, it's not aborting as I would expect:
[TestMethod]
public void RedirectUriUnderTimeout()
{
//arrange
var service = GetService();
A.CallTo(() => _httpRequest.GetResponseAsync()).ReturnsLazily(() => {
Thread.Sleep(TimeSpan.FromSeconds(3));
return new TestWebResponse();
});
A.CallTo(() => _httpRequest.GetResponseString())
.ReturnsLazily(() => VALID_REQUEST_PAYLOAD);
//act
var url = service.GetFinalUrl("https://someplace.com/testurl");
//assert
Assert.IsNull(url);
}
It seems like it waits for the full three seconds, before returning the TestWebResponse that has a non-null ResponseUri.
I don't know if there's something fundamentally wrong with my implementation, or wrong with my test, but obviously I'm blocking an async call in a way I'm not expecting to.
Can someone help me identify what I've done wrong?
public static T ToSynchronousResult<T>(this Task<T> task)
{
return Task.Run(async () => await task).Result;
}
This part causes to get thread blocked.As you mentioned the method ToSynchronousResult, it will block the thread until task result returned. You should follow "async all the way" rule and you should use await. It is only way to apply async efficiently.
public async Task<string> GetFinalUrl(string url)
{
string finalUrl;
try
{
finalUrl = await FollowDestinationUrl(url).TimeoutAfter(TimeSpan.FromSeconds(2));
}
catch (TimeoutException)
{
finalUrl = null;
}
return finalUrl;
}
OK, it looks like I was way overthinking it. #Stormcloak clued me in that what I was doing wasn't going to work, so I started looking at alternatives, and I realized that while the async/ await pattern weren't appropriate here, the TPL library still came in handy.
I changed my FinalDestinationUrl method to synchronous like so:
private string FollowDestinationUrl(string url)
{
var request = _webRequestFactory.CreateGet(url);
var payload = request.GetResponse();
return payload.ResponseUri.ToString();
}
then I called it like so:
var task = Task.Run(() => FollowDestinationUrl(destinationUrl));
finalUrl = task.Wait(TimeSpan.FromSeconds(2)) ? task.Result : null;
Then I changed my unit test to resemble:
[TestMethod]
public void RedirectUriUnderTimeout()
{
//arrange
var service = GetService();
A.CallTo(() => _httpRequest.GetResponse()).ReturnsLazily(() => {
Thread.Sleep(TimeSpan.FromSeconds(3));
return new TestWebResponse();
});
A.CallTo(() => _httpRequest.GetResponseString())
.ReturnsLazily(() => VALID_REQUEST_PAYLOAD);
//act
var url = service.GetFinalUrl("https://someplace.com/testurl");
//assert
Assert.IsNull(url);
}
The test passed. All is well in the world. Thanks!

C# Async/Await call not working

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);
}
}
}

Make Async Rest Request

I am using RestSharp to make some Rest Requests on Windows Phone.
But I am struggling to use "Aync/await" with the functions that I use :
For example with this function :
private void Function()
{
var client = new RestSharp.RestClient("https://exampleapi.com");
client.Authenticator = [....]
var request = new RestSharp.RestRequest("/example.json", Method.GET);
try
{
client.ExecuteAsync(request, reponse =>
{
if (reponse.StatusCode == HttpStatusCode.OK)
{
// Operations with the json...
}
else
{
MessageBox.Show("Error");
}
});
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
I tried to add the word async like this :
private async void restsharptest()
{
var client = new RestSharp.RestClient("https://exampleapi.com");
client.Authenticator = [....]
var request = new RestSharp.RestRequest("/example.json", Method.GET);
try
{
client.ExecuteAsync(request, reponse =>
{
if (reponse.StatusCode == HttpStatusCode.OK)
{
var timeline = JsonConvert.DeserializeObject<List<dynamic>>(reponse.Content);
}
else
{
MessageBox.Show("Error");
}
});
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
Buth then when I try add await :
var timeline = await JsonConvert.DeserializeObject<List<dynamic>>(reponse.Content);
I get the following errors :
Impossible to reach 'System.Collections.Generic.List
and :
Operator 'await' can only be used in a lambda expression async. Mark
this with lambda expression modifier 'async'.
How can I use async/await my "Function1" ?
EDIT :
client.ExecuteAsync(request, response =>
{
if (response.StatusCode == HttpStatusCode.OK)
{
List_ = new List<Myobject>();
List_ = await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<List<Myobject>>(response.Content));
tcs.SetResult(RefreshList_);
}
else
{
MessageBox.Show("Error");
}
});
I have this error again :
Operator 'await' can only be used in a lambda expression async. Mark
this with lambda expression modifier 'async'.
How can I solve this ?
In order to use async you should do the following:
private async void Function()
{
var client = new RestSharp.RestClient("https://exampleapi.com");
client.Authenticator = [....]
var request = new RestSharp.RestRequest("/example.json", Method.GET);
try
{
var response = await client.ExecuteTaskAsync(request);
if (reponse.StatusCode == HttpStatusCode.OK)
{
// Operations with the json...
}
else
{
MessageBox.Show("Error");
}
}
catch (Exception error)
{
MessageBox.Show(error.Message);
}
}
Notice the difference between your ExecuteAsync and the ExecuteTaskAsync with the await before.
You can only await (wait) completion of methods marked as async where return type is either Task or Task<T> (and in special cases void). async keyword allows the use of await keyword inside the method/lambda.
Marking lambda as async
class.Method(() => { /* Do something sync*/ };
class.Method(async () => { /* Do something async */ };
In your case you could do something like
{
...
var client = new RestClient(serviceBaseUrl);
var request = new RestRequest(serviceUrl, Method.GET);
var content = await client.ExecuteTaskAsync(request);
var somethingToReturn = await Task.Factory.StartNew(() => JsonConvert.DeserializeObject<List<MyClass>>(content));
...
}

C# - How to run multi await in one method?

I don't know how to run multi await methods in single method. For example my code as below:
public static async Task<bool> Authenticate()
{
bool authen = false;
string message = String.Empty;
try
{
session = await FacebookSessionClient.LoginAsync("user_about_me,read_stream");
fbAccessToken = session.AccessToken;
fbFacbookID = session.FacebookId;
await saveProfile(fbFacebookID); //error here,my app is closed at here
authen = true;
}
catch (InvalidOperationException e)
{
authen = false;
}
return authen;
}
And I have method save profile
public async static void saveProfile(string fbFacbookID)
{
string response = string.Empty;
if (!string.IsNullOrEmpty(fbFacbookID))
{
response=await StaticClass.getJsonStream(string.Format("http://graph.facebook.com/{0}", fbFacbookID));
JObject _object = JObject.Parse(response);
SaveValueSetting("usernameFB",(string)_object["username"]);
}
else
{
return;
}
}
But I cannot run method? So how do I fix it?
you can use below mentioned code.
private void Button_Click_1(object sender, RoutedEventArgs e)
{
MyMethod();
MyMethod1();
}
public async Task MyMethod()
{
Task<int> longRunningTask = LongRunningOperation();
//indeed you can do independent to the int result work here
//and now we call await on the task
int result = await longRunningTask;
//use the result
MessageBox.Show(result.ToString());
}
public async Task MyMethod1()
{
Task<int> longRunningTask = SecondMethod();
//indeed you can do independent to the int result work here
//and now we call await on the task
int result = await longRunningTask;
//use the result
MessageBox.Show(result.ToString());
}
public async Task<int> LongRunningOperation() // assume we return an int from this long running operation
{
await Task.Delay(5000); //5 seconds delay
return 1;
}
public async Task<int> SecondMethod()
{
await Task.Delay(2000);
return 1;
}

Categories