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));
...
}
Related
How can I write test cases for Generic Http methods. My methods are below.
public async Task<T> HttpGetAsync<T>(string urlSuffix)
{
var url = Common.FormatUrl(urlSuffix, _instanceUrl, _apiVersion);
return await HttpGetAsync<T>(url);
}
public async Task<T> HttpGetAsync<T>(Uri uri)
{
try
{
var response = await HttpGetAsync(uri);
var jToken = JToken.Parse(response);
if (jToken.Type == JTokenType.Array)
{
var jArray = JArray.Parse(response);
return JsonConvert.DeserializeObject<T>(jArray.ToString());
}
// else
try
{
var jObject = JObject.Parse(response);
return JsonConvert.DeserializeObject<T>(jObject.ToString());
}
catch
{
return JsonConvert.DeserializeObject<T>(response);
}
}
catch (BaseHttpClientException e)
{
throw ParseForceException(e.Message);
}
}
protected async Task<string> HttpGetAsync(Uri uri)
{
var responseMessage = await _httpClient.GetAsync(uri).ConfigureAwait(false);
if (responseMessage.StatusCode == HttpStatusCode.NoContent)
{
return string.Empty;
}
var response = await responseMessage.Content.ReadAsStringAsync().ConfigureAwait(false);
if (responseMessage.IsSuccessStatusCode)
{
return response;
}
throw new BaseHttpClientException(response, responseMessage.StatusCode);
}
I'm trying to call an Api. If the call fails, I'm retrying with in the configured time out. When I'm writing the unit test for the scenario where the api repeated calls fails and the time out happens. I'm unable to determine what to Assert here. I think it's obvious to verify that the mockedBaseApiClient has never returned the response success for any of it's call in the execution. But I can't figure out how to verify the return type on the mocked object.
public async Task UpdateDocumentPath(UpdateDocument doc)
{
var path = $"v1/documents/{doc.accountId}/{doc.documentId}/paths";
try
{
var response = await _baseApiClient.PutAsync(DocumentsApiKey, path, doc);
if (response.IsSuccessStatusCode)
{
var updatedDocument = await response.Deserialize<UpdateDocument>();
var updatedPath = updatedDocument.documentPath;
}
else
{
await TryToReConnect(doc);
}
}
catch (Exception ex)
{
_exceptionPublisher.PublishException(ex);
await TryToReConnect(doc);
}
}
My Unit Test:
[Fact]
public async Task DocumentPatchAdapter_PatchDocument_RetriesWhenUnSuccessfullStatusCode_ButTimeoutExhausts_Tests()
{
MockConfiguration();
_mockedConfigurationSection.SetupGet(c => c.Value).Returns("20000");
HttpResponseMessage notFoundResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.NotFound
};
_mockedBaseApiClient
.SetupSequence(c => c.PutAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<Object>()))
.ReturnsAsync(notFoundResponse)
.ReturnsAsync(notFoundResponse)
.ReturnsAsync(notFoundResponse);
UpdateDocument documentPathToBeUpdated = new UpdateDocument
{
accountId = 34512274,
documentPath = "\\\\sharoi.vliproj.com\\DevL\\DocumentMaker\\Print\\InsuranceScoreRenew_19196100600.pdf",
documentId = 3656261
};
await _documentPatchAdapter.UpdateDocumentPath(documentPathToBeUpdated);
//_mockedBaseApiClient.Verify(c=>c.PutAsync(.....)).NeverReturns(SuccessCode); I want something like this here
}
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";
}))();
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.
I want to asynchronously access DropBox API in a MonoTouch app.
I thought it would be convenient to use DropNet which itself relies on RestSharp.
Both libraries work well but DropNet overloads that return Tasks don't give you a way to associate requests with cancellation tokens.
This is how their implementation looks:
public Task<IRestResponse> GetThumbnailTask(string path, ThumbnailSize size)
{
if (!path.StartsWith("/")) path = "/" + path;
var request = _requestHelper.CreateThumbnailRequest(path, size, Root);
return ExecuteTask(ApiType.Content, request, cancel);
}
ExecuteTask implementation is based on TaskCompletionSource and was originally written by Laurent Kempé:
public static class RestClientExtensions
{
public static Task<TResult> ExecuteTask<TResult>(
this IRestClient client, IRestRequest request
) where TResult : new()
{
var tcs = new TaskCompletionSource<TResult>();
WaitCallback asyncWork = _ => {
try {
client.ExecuteAsync<TResult>(request,
(response, asynchandle) => {
if (response.StatusCode != HttpStatusCode.OK) {
tcs.SetException(new DropboxException(response));
} else {
tcs.SetResult(response.Data);
}
}
);
} catch (Exception exc) {
tcs.SetException(exc);
}
};
return ExecuteTask(asyncWork, tcs);
}
public static Task<IRestResponse> ExecuteTask(
this IRestClient client, IRestRequest request
)
{
var tcs = new TaskCompletionSource<IRestResponse>();
WaitCallback asyncWork = _ => {
try {
client.ExecuteAsync(request,
(response, asynchandle) => {
if (response.StatusCode != HttpStatusCode.OK) {
tcs.SetException(new DropboxException(response));
} else {
tcs.SetResult(response);
}
}
);
} catch (Exception exc) {
tcs.SetException(exc);
}
};
return ExecuteTask(asyncWork, tcs);
}
private static Task<TResult> ExecuteTask<TResult>(
WaitCallback asyncWork, TaskCompletionSource<TResult> tcs
)
{
ThreadPool.QueueUserWorkItem(asyncWork);
return tcs.Task;
}
}
How do I change or extend this code to support cancellation with CancellationToken?
I'd like to call it like this:
var task = dropbox.GetThumbnailTask(
"/test.jpg", ThumbnailSize.ExtraLarge2, _token
);
Because CancellationToken is a value type, we can add it as an optional parameter to the APIs with default value and avoid null checks, which is sweet.
public Task<IRestResponse> GetThumbnailTask(
string path, ThumbnailSize size, CancellationToken cancel = default(CancellationToken)
) {
if (!path.StartsWith("/")) path = "/" + path;
var request = _requestHelper.CreateThumbnailRequest(path, size, Root);
return ExecuteTask(ApiType.Content, request, cancel);
}
Now, RestSharp ExecuteAsync method returns RestRequestAsyncHandle that encapsulates underlying HttpWebRequest, along with Abort method. This is how we cancel things.
public static Task<TResult> ExecuteTask<TResult>(
this IRestClient client, IRestRequest request, CancellationToken cancel = default(CancellationToken)
) where TResult : new()
{
var tcs = new TaskCompletionSource<TResult>();
try {
var async = client.ExecuteAsync<TResult>(request, (response, _) => {
if (cancel.IsCancellationRequested || response == null)
return;
if (response.StatusCode != HttpStatusCode.OK) {
tcs.TrySetException(new DropboxException(response));
} else {
tcs.TrySetResult(response.Data);
}
});
cancel.Register(() => {
async.Abort();
tcs.TrySetCanceled();
});
} catch (Exception ex) {
tcs.TrySetException(ex);
}
return tcs.Task;
}
public static Task<IRestResponse> ExecuteTask(this IRestClient client, IRestRequest request, CancellationToken cancel = default(CancellationToken))
{
var tcs = new TaskCompletionSource<IRestResponse>();
try {
var async = client.ExecuteAsync<IRestResponse>(request, (response, _) => {
if (cancel.IsCancellationRequested || response == null)
return;
if (response.StatusCode != HttpStatusCode.OK) {
tcs.TrySetException(new DropboxException(response));
} else {
tcs.TrySetResult(response);
}
});
cancel.Register(() => {
async.Abort();
tcs.TrySetCanceled();
});
} catch (Exception ex) {
tcs.TrySetException(ex);
}
return tcs.Task;
}
Finally, Lauren's implementation puts requests in thread pool but I don't see a reason to do so—ExecuteAsync is asynchronous itself. So I don't do that.
And that's it for cancelling DropNet operations.
I also made a few tweaks which may be useful to you.
Because I had no way of scheduling DropBox Tasks without resorting to wrapping ExecuteTask calls into another Tasks, I decided to find an optimal concurrency level for requests, which turned out to be 4 for me, and set it explicitly:
static readonly Uri DropboxContentHost = new Uri("https://api-content.dropbox.com");
static DropboxService()
{
var point = ServicePointManager.FindServicePoint(DropboxContentHost);
point.ConnectionLimit = 4;
}
I was also content with letting unhandled task exceptions rot in hell, so that's what I did:
TaskScheduler.UnobservedTaskException += (sender, e) => {
e.SetObserved();
};
One last observation is you shouldn't call Start() on a task returned by DropNet because the task starts right away. If you don't like that, you'll need to wrap ExecuteTask in yet another “real” task not backed by TaskCompletionSource.