Unit Test case for Generic HttpGet methods - c#

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

Related

Xamarin - Logout when token expires

I have an Api hosted on Azure which I consume on my Xamarin Forms project.
I show the login page at the beginning and I check if the JWT token has expired but I also want to check that on each http method in case it expires while the user is using the app.
So I need to either show the user the login page and tell them to login again I have been searching how to do that I can't get it right.
Here is my AzureApiService class.
public class AzureApiService
{
HttpClient httpClient;
public AzureApiService()
{
#if DEBUG
var httpHandler = new HttpClientHandler
{
ServerCertificateCustomValidationCallback = (o, cert, chain, errors) => true
};
#else
var httpHandler = new HttpClientHandler();
#endif
httpClient = new HttpClient(httpHandler);
httpClient.Timeout = TimeSpan.FromSeconds(15);
httpClient.MaxResponseContentBufferSize = 256000;
}
public async Task<string> LoginAsync(string url, AuthUser data)
{
var user = await HttpLoginPostAsync(url, data);
if (user != null)
{
//Save data on constants
CurrentPropertiesService.SaveUser(user);
return user.Token;
}
else
{
return string.Empty;
}
}
// Generic Get Method
public async Task<T> HttpGetAsync<T>(string url, string token)
{
T result = default(T);
try
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = httpClient.GetAsync(url).Result;
HttpContent content = response.Content;
if (response.IsSuccessStatusCode)
{
var jsonResponse = await content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
}
else
{
if (IsExpired(token))
{
await Logout();
}
throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase);
}
}
catch (Exception ex)
{
OnError(ex.ToString());
}
return result;
}
// Generic Post Method
public async Task<T> HttpPostAsync<T>(string url, string token, T data)
{
T result = default(T); // résultat de type générique
try
{
string json = JsonConvert.SerializeObject(data);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.PostAsync(new Uri(url), content);
var jsonResponse = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var jsons = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
}
else
{
if (IsExpired(token))
{
await Logout();
}
throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase);
}
return result;
}
catch (Exception ex)
{
OnError(ex.ToString());
return result;
}
}
// Generic Put Method
public async Task<T> HttpPutAsync<T>(string url, string token, T data)
{
T result = default(T); // résultat de type générique
try
{
string json = JsonConvert.SerializeObject(data);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.PutAsync(new Uri(url), content);
if (response.IsSuccessStatusCode)
{
var jsonResponse = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
}
else
{
if (IsExpired(token))
{
await Logout();
}
throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase);
}
return result;
}
catch (Exception ex)
{
OnError(ex.ToString());
return result;
}
}
// Generic Delete Method
public async Task<bool> HttpDeleteAsync(string url, string token)
{
try
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.DeleteAsync(url);
if (response.IsSuccessStatusCode)
{
return true;
}
else
{
if (IsExpired(token))
{
await Logout();
}
return false;
throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase);
}
}
catch (Exception ex)
{
OnError(ex.ToString());
return false;
}
}
// Login Post Method
public async Task<T> HttpLoginPostAsync<T>(string url, T data)
{
T result = default(T); // résultat de type générique
try
{
string json = JsonConvert.SerializeObject(data);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(new Uri(url), content);
if (response.IsSuccessStatusCode)
{
var jsonResponse = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
}
else
{
throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase);
}
return result;
}
catch (Exception ex)
{
OnError(ex.ToString());
return result;
}
}
public bool IsExpired(string token)
{
if (token == null || "".Equals(token))
{
return true;
}
/***
* Make string valid for FromBase64String
* FromBase64String cannot accept '.' characters and only accepts stringth whose length is a multitude of 4
* If the string doesn't have the correct length trailing padding '=' characters should be added.
*/
int indexOfFirstPoint = token.IndexOf('.') + 1;
String toDecode = token.Substring(indexOfFirstPoint, token.LastIndexOf('.') - indexOfFirstPoint);
while (toDecode.Length % 4 != 0)
{
toDecode += '=';
}
//Decode the string
string decodedString = Encoding.ASCII.GetString(Convert.FromBase64String(toDecode));
//Get the "exp" part of the string
Regex regex = new Regex("(\"exp\":)([0-9]{1,})");
Match match = regex.Match(decodedString);
long timestamp = Convert.ToInt64(match.Groups[2].Value);
DateTime date = new DateTime(1970, 1, 1).AddSeconds(timestamp);
DateTime compareTo = DateTime.UtcNow;
int result = DateTime.Compare(date, compareTo);
return result < 0;
}
private async Task Logout()
{
CurrentPropertiesService.Logout();
CurrentPropertiesService.RemoveCart();
await Shell.Current.GoToAsync($"//main");
}
private void OnError(string error)
{
Console.WriteLine("[WEBSERVICE ERROR] " + error);
}
}
So you can see that in each http method I'm trying yo check if the token has expired already and then logout but it just gives an error.
On my Logout method I just want to delete all the properties and then navigate to the login page but it isn't working.
Please help I would like to know how to do this. Thanks.
EDIT
Trying to implement DelegatingHandler stops at SendAsync
Here is my HttpDelegatingHandler class
public class HttpDelegatingHandler : DelegatingHandler
{
public HttpDelegatingHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("Bearer", CurrentPropertiesService.GetToken());
// before request
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// after request
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
await Logout();
}
return response;
}
private async Task Logout()
{
CurrentPropertiesService.Logout();
CurrentPropertiesService.RemoveCart();
await Shell.Current.GoToAsync($"//main");
}
}
Here my AzureApiService class
public class AzureApiService
{
HttpClient httpClient;
public AzureApiService()
{
var clientHandler = new HttpClientHandler();
#if DEBUG
clientHandler.ServerCertificateCustomValidationCallback =
(sender, cert, chain, sslPolicyErrors) =>
{
return true;
};
#endif
httpClient = new HttpClient(new HttpDelegatingHandler(clientHandler));
httpClient.Timeout = TimeSpan.FromSeconds(15);
httpClient.MaxResponseContentBufferSize = 256000;
}
public async Task<string> LoginAsync(string url, AuthUser data)
{
var user = await HttpLoginPostAsync(url, data);
if (user != null)
{
//Save data on constants
CurrentPropertiesService.SaveUser(user);
return user.Token;
}
else
{
return string.Empty;
}
}
// Generic Get Method
public async Task<T> HttpGetAsync<T>(string url, string token)
{
T result = default(T);
try
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = await httpClient.GetAsync(url);
HttpContent content = response.Content;
var jsonResponse = await content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
throw new Exception(((int)response.StatusCode).ToString() + " - " + response.ReasonPhrase);
}
catch (Exception ex)
{
OnError(ex.ToString());
}
return result;
}
It works for PostAsync
// Login Post Method
public async Task<T> HttpLoginPostAsync<T>(string url, T data)
{
T result = default(T); // résultat de type générique
try
{
string json = JsonConvert.SerializeObject(data);
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await httpClient.PostAsync(new Uri(url), content);
var jsonResponse = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
return result;
}
catch (Exception ex)
{
OnError(ex.ToString());
return result;
}
}
But as I said it stops when trying to get data
You can handle 401 Unauthorized response in a custom Delegating handler. This way you can handle anything before and after request execution in a single place.
public class HttpDelegatingHandler : DelegatingHandler
{
public HttpDelegatingHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
request.Headers.Add("Authorization", string.Format("Basic {0}", MyUserRepository.AuthToken));
// before request
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
// after request
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
await Shell.Current.GoToAsync($"//main");
}
return response;
}
}
public class AzureApiService
{
HttpClient httpClient;
public AzureApiService()
{
var clientHandler = new HttpClientHandler();
#if DEBUG
clientHandler.ServerCertificateCustomValidationCallback =
(sender, cert, chain, sslPolicyErrors) =>
{
return true;
};
#endif
httpClient = new HttpClient(new HttpDelegatingHandler(clientHandler));
httpClient.Timeout = TimeSpan.FromSeconds(15);
httpClient.MaxResponseContentBufferSize = 256000;
}
....
// Generic Get Method
public async Task<T> HttpGetAsync<T>(string url, string token)
{
T result = default(T);
try
{
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
HttpResponseMessage response = await httpClient.GetAsync(url);
var jsonResponse = await response.Content.ReadAsStringAsync();
result = JsonConvert.DeserializeObject<T>(jsonResponse);
}
catch (Exception ex)
{
OnError(ex.ToString());
}
return result;
}

Mock returns null value when ReturnResult is a custom object but works as expected when it is a primitive type bool

I am using Moq in .net core(1.1) and having a bit of torrid time understanding this behavior as all the examples on interweb points to the fact the this should work with no issues.
I have already tried with:
Returns(Task.FromResult(...)
Returns(Task.FromResult(...)
ReturnsAsync(...)
Mocking a IHttpClient interface to wrap PostAsync, PutAsync and GetAsync. All of these return an ApiResponse object.
var mockClient = new Mock<IHttpClient>();
Does not work:
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(new ApiResponse()));
PostSync definition:
public async Task<ApiResponse> PostAsync(string url, string body, string authToken = null)
Does work:
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null))
.Returns(Task.FromResult(bool));
PostSync definition:
public async Task<bool> PostAsync(string url, string body, string authToken = null)
Usage:
var api = new ApiService(mockClient.Object);
var response = api.LoginAsync(body.Username, body.Password);
UPDATE
[Fact]
public async void TestLogin()
{
var mockClient = new Mock<IHttpClient>();
mockClient.Setup(x => x.PostAsync(url, JsonConvert.SerializeObject(body), null)).Returns(Task.FromResult(new ApiResponse()));
var api = new ApiService(mockClient.Object);
var response = await api.LoginAsync(body.Username, body.Password);
Assert.IsTrue(response);
}
Return Type:
public class ApiResponse
{
public string Content { get; set; }
public HttpStatusCode StatusCode { get; set; }
public string Reason { get; set; }
}
LoginAsync:
public async Task<bool> LoginAsync(string user, string password)
{
var body = new { Username = user, Password = password };
try
{
var response = await _http.PostAsync(_login_url, JsonConvert.SerializeObject(body), null);
return response .State == 1;
}
catch (Exception ex)
{
Logger.Error(ex);
return false;
}
}
PostAsync:
public async Task<object> PostAsync(string url, string body, string authToken = null)
{
var client = new HttpClient();
var content = new StringContent(body, Encoding.UTF8, "application/json");
var response = await client.PostAsync(new Uri(url), content);
var resp = await response.Result.Content.ReadAsStringAsync();
return new ApiResponse
{
Content = resp,
StatusCode = response.Result.StatusCode,
Reason = response.Result.ReasonPhrase
};
}
Assuming a simple method under test like this based on minimal example provided above.
public class ApiService {
private IHttpClient _http;
private string _login_url;
public ApiService(IHttpClient httpClient) {
this._http = httpClient;
}
public async Task<bool> LoginAsync(string user, string password) {
var body = new { Username = user, Password = password };
try {
var response = await _http.PostAsync(_login_url, JsonConvert.SerializeObject(body), null);
return response.StatusCode == HttpStatusCode.OK;
} catch (Exception ex) {
//Logger.Error(ex);
return false;
}
}
}
The following test works when configured correctly
[Fact]
public async Task Login_Should_Return_True() { //<-- note the Task and not void
//Arrange
var mockClient = new Mock<IHttpClient>();
mockClient
.Setup(x => x.PostAsync(It.IsAny<string>(), It.IsAny<string>(), null))
.ReturnsAsync(new ApiResponse() { StatusCode = HttpStatusCode.OK });
var api = new ApiService(mockClient.Object);
//Act
var response = await api.LoginAsync("", "");
//Assert
Assert.IsTrue(response);
}
The above is just for demonstrative purposes only to show that it can work provided the test is configured properly and exercised based on the expected behavior.
Take some time and review the Moq quick start to get a better understanding of how to use the framework.

How to post a webapi call using async and await

I am trying write a webapi which tries to post a webapi call using async and await,my current issue is as soon as I call await client.PostAsync(url, content); it hangs.
1.How to debug why it is hanging?
2.Is there a way to do it without async and await?I want to do it sequentially
public static async Task<string> testWCF2(string xmlConfig)
{
string submitOut;
using (var client = new System.Net.Http.HttpClient())
{
var url = "http://server:8100/api/SoftwareProductBuild";
var content = new StringContent(xmlConfig, Encoding.UTF8, "application/xml");
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
var responseBody = await response.Content.ReadAsStringAsync();
submitOut = responseBody;
}
else
{
submitOut = string.Format("Bad Response {0} \n", response.StatusCode.ToString());
submitOut = submitOut + response;
}
}
return submitOut;
}
public async Task<string> QlasrSubmit(List<XMLSiInfo> xmlConfigs)
{
string submitOut = "QLASR: ";
foreach (XMLSiInfo xmlConfig in xmlConfigs)
{
submitOut = submitOut + "\n" + await testWCF2(xmlConfig.xml);
}
return submitOut;
}
public async Task<string> QlasrPostcommit(string si, string sp, string variant = null)
{
.....
string submitStatus = await QlasrSubmit(siInfo);
.....
return submitStatus;
}
Service:
public async Task<string> QlasrPostcommit(string si, string sp, string variant = null)
{
return await DPR.QlasrPostcommit(si, sp, variant);
}
Controller:
[Route("api/DevPool/QlasrPostcommit")]
[HttpPost]
public ResponseObject QlasrPostcommit(string si, string sp, string variant = null)
{
ResponseObject response = new ResponseObject();
try
{
response.status = 200;
response.data = DPS.QlasrPostcommit(si, sp, variant);
return response;
}
catch (Exception e)
{
response.status = 200;
response.data = null;
response.message = e.Message;
return response;
}
}
You should use async all the way, as I mentioned in your previous question:
[Route("api/DevPool/QlasrPostcommit")]
[HttpPost]
public async Task<ResponseObject> QlasrPostcommit(string si, string sp, string variant = null)
{
ResponseObject response = new ResponseObject();
try
{
response.status = 200;
response.data = await DPS.QlasrPostcommit(si, sp, variant);
return response;
}
catch (Exception e)
{
response.status = 200;
response.data = null;
response.message = e.Message;
return response;
}
}
In this particular case, you're running into a deadlock because you're blocking on asynchronous code.
I solved it and it works perfectly, without deallock and with waiting result!!
You have fix the Service:
public string QlasrPostcommit(string si, string sp, string variant = null)
{
Task<string > task = Task.Run<string >(async () => await
DPR.QlasrPostcommit(si, sp, variant));
task.Result;
}
Generic answer:
public TypeToReturn MyAsyncMethod(myParams...)
{
Task<TypeToReturn> task = Task.Run<TypeToReturn>(async () => await
MyAsyncMethod(myParams...));
task.Result;
}

Reading an HttpError result from HttpResponseMessage without using exceptions

I'm trying to pull an HttpError out of an HttpResponseMessage message which may or not be there. If the Api throws an exception it will be serialised as an HttpError however errors such as 404's will not be in this format.
I've managed to fix this bug in the code below by catching to exception thrown if we fail to deserialize the HttpError.
The issue is now I'm using exception driven development.
Idealy I want something like this.
var httpError = await response.Content.TryReadAsAsync<HttpError>(formatters);
if (httpError == null)
{
// Definetly not an HttpError and no exception thrown
}
Surely the must be an easy way of telling the type of the content in the HttpContent?
public static async Task<ApiResponseMessage<T>> GetApiResponseAsync<T>(this HttpResponseMessage response, IEnumerable<MediaTypeFormatter> formatters) where T : class
{
if (!response.IsSuccessStatusCode)
{
HttpError httpError;
// Exception driven programming
try
{
// Could use string?
var contentString = response.Content.ReadAsStringAsync();
// This doesn't work. Throws exception if not correct type
var contentObject = await response.Content.ReadAsAsync<object>();
var alwaysNull = contentObject as HttpError;
httpError = await response.Content.ReadAsAsync<HttpError>(formatters);
}
catch (Exception)
{
httpError = null;
}
return new ApiResponseMessage<T>
{
IsSuccess = false,
HttpError = httpError,
Response = response
};
}
return new ApiResponseMessage<T>
{
IsSuccess = true,
Result = await response.Content.ReadAsAsync<T>(formatters),
Response = response
};
}
Cleaned up the code so it at least compiles.
public class ReadAsyncResult<T>
{
public ReadAsyncResult()
{
}
public ReadAsyncResult(T result)
{
Result = result;
IsSuccess = result != null;
}
public T Result { get; set; }
public bool IsSuccess { get; set; }
public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(HttpContent content)
{
return await TryReadAsAsync<T>(content, CancellationToken.None);
}
public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(HttpContent content,
CancellationToken cancellationToken)
{
if (content == null)
return new ReadAsyncResult<T>();
var type = typeof(T);
var objectContent = content as ObjectContent;
if (objectContent?.Value != null && type.IsInstanceOfType(objectContent.Value))
{
return new ReadAsyncResult<T>((T) objectContent.Value);
}
var mediaType = content.Headers.ContentType;
var reader =
new MediaTypeFormatterCollection(new MediaTypeFormatterCollection()).FindReader(type, mediaType);
if (reader == null) return new ReadAsyncResult<T>();
var value = await ReadAsAsyncCore<T>(content, type, reader, cancellationToken);
return new ReadAsyncResult<T>(value);
}
private static async Task<T> ReadAsAsyncCore<T>(HttpContent content, Type type, MediaTypeFormatter formatter,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var stream = await content.ReadAsStreamAsync();
var result = await formatter.ReadFromStreamAsync(type, stream, content, null, cancellationToken);
return (T) result;
}
}
It is of course, blindingly simple.
var message = new HttpResponseMessage();
HttpError httpError;
message.TryGetContentValue(out httpError);
if (httpError != null)
{
// Do stuff
}
Edit:
This didn't fix my issue as the content type was not of type ObjectResult. I was expecting the TryGetContentValue to work in the same way as HttpContent.ReadAsAsync.
After digging through the source code for ReadAsAsync I have created a working solution.
public class ReadAsyncResult<T>
{
public ReadAsyncResult()
{
}
public ReadAsyncResult(T result)
{
Result = result;
IsSuccess = result != null;
}
public T Result { get; set; }
public bool IsSuccess { get; set; }
}
public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(this HttpContent content)
{
return await TryReadAsAsync<T>(content, CancellationToken.None);
}
public static async Task<ReadAsyncResult<T>> TryReadAsAsync<T>(this HttpContent content, CancellationToken cancellationToken)
{
if (content == null)
return new ReadAsyncResult<T>();
var type = typeof(T);
var objectContent = content as ObjectContent;
if (objectContent?.Value != null && type.IsInstanceOfType(objectContent.Value))
{
return new ReadAsyncResult<T>((T)objectContent.Value);
}
var mediaType = content.Headers.ContentType;
var reader = new MediaTypeFormatterCollection(new MediaTypeFormatterCollection()).FindReader(type, mediaType);
if (reader == null) return new ReadAsyncResult<T>();
var value = await ReadAsAsyncCore<T>(content, type, reader, cancellationToken);
return new ReadAsyncResult<T>(value);
}
private static async Task<T> ReadAsAsyncCore<T>(HttpContent content, Type type, MediaTypeFormatter formatter, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var stream = await content.ReadAsStreamAsync();
var result = await formatter.ReadFromStreamAsync(type, stream, content, null, cancellationToken);
return (T) result;
}

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

Categories