Error with await operator - c#

There is problem with my code. How can I solve this problem? This problem in await operator.
public MyModel()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://api.vkontakte.ru/method/video.get?uid=219171498&access_token=d61b93dfded2a37dfcfa63779efdb149653292636cac442e53dae9ba6a049a75637143e318cc79e826149");
string googleSearchText = await response.Content.ReadAsStringAsync();
JObject googleSearch = JObject.Parse(googleSearchText);
IList<JToken> results = googleSearch["response"].Children().Skip(1).ToList();
IList<MainPage1> searchResults = new List<MainPage1>();
foreach (JToken result in results)
{
MainPage1 searchResult = JsonConvert.DeserializeObject<MainPage1>(result.ToString());
searchResults.Add(searchResult);
}

You're trying to use await within a constructor. You can't do that - constructors are always synchronous.
You can only use await within a method or anonymous function with the async modifier; you can't apply that modifier to constructors.
One approach to fixing this would be to create a static async method to create an instance - that would do all the relevant awaiting, and then pass the results to a simple synchronous constructor. Your callers would then need to handle this appropriately, of course.
public static async Task<MyModel> CreateInstance()
{
string googleSearchText;
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage response = await client.GetAsync(...))
{
googleSearchText = await response.Content.ReadAsStringAsync();
}
}
// Synchronous constructor to do the rest...
return new MyModel(googleSearchText);
}

You can't use await in the constructor of a class.
An async method returns a Task object which can be executed async. A constructor does not have a return type and thus can't return a Task object, and thus can't be awaited.
A simple fix for this problem is create a Init function:
public MyModel()
{
}
public async Task Init()
{
HttpClient client = new HttpClient();
HttpResponseMessage response = await client.GetAsync("https://api.vkontakte.ru/method/video.get?uid=219171498&access_token=d61b93dfded2a37dfcfa63779efdb149653292636cac442e53dae9ba6a049a75637143e318cc79e826149");
string googleSearchText = await response.Content.ReadAsStringAsync();
JObject googleSearch = JObject.Parse(googleSearchText);
IList<JToken> results = googleSearch["response"].Children().Skip(1).ToList();
IList<MainPage1> searchResults = new List<MainPage1>();
foreach (JToken result in results)
{
MainPage1 searchResult = JsonConvert.DeserializeObject<MainPage1>(result.ToString());
searchResults.Add(searchResult);
}
}
Then when you create your model:
var model = new MyModel();
await model.Init();

Related

httpclient sendasync and return object will trigger two times

I have below code which use httpclient and use sendasync, when I test, it always run twice on API.
Controller :
[HttpGet("GetAllStores")]
public async Task<bookstores> GetAllStores()
{
Console.writeline("Trigger Stores")
return await dbContext.set<bookstores>().toListAsync()
}
httpclient
public async Task<IEnumerable<bookstores>> FetchAllStores()
{
var requestContent = new HttpRequestMessage
{
Method = HttpMethod.Get
};
var response = await httpClient.SendAsync("http://127.0.0.1:5000/GetAllStores", HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
return JsonSerializer.Deserialize<bookstores>(await response.Content.ReadAsStringAsync(), defaultJsonSerializerOptions);
}
Test
public async Task GetSettingProfile_AsExpected()
{
var sut = new ApiClient(
new HttpClient() { BaseAddress=new Uri("http://localhost:40331") });
await sut.FetchAllStores();
}
The output in console is show Trigger Stores two times
Can I know how to make it which call API in one time ?

await operator giving issue when using with lambda

I have 2 Entity and I want to copy some data from Second Entity to First Entity and after that I want to return a simple string saying Success.I am using Polly to make http request.I am planning to get data in json and then convert it in my Entity model and do the manipulation which I am able to do but Calling both the task which return differnt types(can be slight different data model) giving some error.I am not so good in Multithreading approach.
public interface IMyRepository
{
string ValidateData(MyData myData);
}
public class MyRepository :IMyRepository
{ private readonly RetryPolicy<HttpResponseMessage> _httpRequestPolicy;
public MyRepository()
{
_httpRequestPolicy = Policy.HandleResult<HttpResponseMessage>(
r => r.StatusCode == HttpStatusCode.InternalServerError)
.WaitAndRetryAsync(3,
retryAttempt => TimeSpan.FromSeconds(retryAttempt), (exception, timeSpan, retryCount, context1) =>
{
var msg = $"Retry {retryCount} implemented with Pollys RetryPolicy " +
$"of {context1.PolicyKey} " +
$"at {context1.ExecutionKey}, " +
$"due to: {exception}.";
});
}
public string ValidateData(MyData MyData)
{
var MyDataOne= Task<MyData>.Factory.StartNew(() => await MyRepository.getProfileOne());
var MyDataTwo= Task<MyData>.Factory.StartNew(() => await MyRepository.getProfileTwo());
//Update some property of MyDataOne on basis of MyDataTwo and return true or fasle in variable **result**
return result;
}
public static async Task<InsuranceCompanyData> getCusomerProfile()
{
var httpClient = GetHttpClient();
string requestEndpoint = "numbers/Get";
HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));
IEnumerable<int> numbers = await httpResponse.Content.ReadAsAsync<IEnumerable<int>>();
return new InsuranceCompanyData();
}
private static HttpClient GetHttpClient()
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(#"http://localhost:2351/api/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return httpClient;
}
}
public static async Task<MyData> getProfileOne()
{
var httpClient = GetHttpClient();
string requestEndpoint = "/numbers/Get1";
HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));
// IEnumerable<string> data1= await httpResponse.Content.ReadAsAsync<IEnumerable<string>>();
return new MyData();
}
public static async Task<MyData> getProfileTwo()
{
var httpClient = GetHttpClient();
string requestEndpoint = "/numbers/Get2";
HttpResponseMessage httpResponse = await _httpRequestPolicy.ExecuteAsync(() => httpClient.GetAsync(requestEndpoint));
// IEnumerable<string> data2= await httpResponse.Content.ReadAsAsync<IEnumerable<string>>();
return new MyyData();
}
private static HttpClient GetHttpClient()
{
var httpClient = new HttpClient();
httpClient.BaseAddress = new Uri(#"http://localhost:2351/api/");
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
return httpClient;
}
I get these errors:
The 'await' operator can only be used within an async lambda expression. Consider marking this lambda expression with the 'async' modifier.
And
An object reference is required for the non-static field, method, or property 'MyRepository._httpRequestPolicy'
Instead of using Task.Factory.StartNew which is not recommended and doesn't support async lambdas (which you don't even need here), use Task.Run:
var profileOneTask = Task.Run(() => getProfileOne());
var profileTwoTask = Task.Run(() => getProfileTwo());
Notice that I changed the variable names to reflect what they actually are. They are tasks that may, at some point, have a result. They are not the result of those operations.
For the second problem, you declared _httpRequestPolicy as an instance member when you should have declared it as a static member for it to be usable without an instance. As discussed in the comments, though, you could just make getProfileOne and getProfileTwo instance methods.
Why you don't change ValidateData signature and add async keyword to method ?
public async Task<string> ValidateDataAsync(MyData MyData)
{
var task1 = Task<MyData>.Factory.StartNew(() => MyRepository.getProfileOne());
var task2 = Task<MyData>.Factory.StartNew(() => MyRepository.getProfileTwo());
await Task.WhenAll(task1, task2)
//Update some property of MyDataOne on basis of MyDataTwo and return true or fasle in variable **result**
return result;
}
As #Camilo Terevinto said it's better to use Task.Run instead of TaskFactory.StartNew.
Task.Run vs Task.Factory.StartNew

WebAPI: using async methods in business logic

The aim is to make controller that uses async method in my custom service.
Controller:
[Route("api/data/summary")]
[HttpGet]
public async Task<IHttpActionResult> Get()
{
var result = await DataService.GetDataObjects();
return Ok(result);
}
Service:
public static async Task<IEnumerable<DataObject>> GetDataObjects()
{
var apiKey = "some-api-key";
var path = "path-to-external-service";
using (var client = new HttpClient())
{
var dataToProcess = // some data object
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
client.BaseAddress = new Uri(path);
HttpResponseMessage response = await client.PostAsJsonAsync("", dataToProcess);
var content = await response.Content.ReadAsStringAsync();
var result = MakeEntities(content); // some logic
return result;
}
}
But I came across with the problem that controller's action returns empty result before service actually finished processing data.
Could you please advice how to implement it correctly?
Your code is OK and controller doesn't seem to return a value before GetDataObjects returns value.
Except for the situations below:
MakeEntities uses some asynchronous operation and you don't await it inside MakeEntities. So MakeEntities return task.
Exception rises while your code is running. Make sure GetDataObjects and MakeEntities code works fine.
The aim is to make controller that uses async method in my custom service.
Controller:
[HttpGet]
[Route("api/data/summary")]
public async Task<IHttpActionResult> Get()
{
var result = await DataService.GetDataObjects().ConfigureAwait(false);
return Ok(result);
}
Service:
public static async Task<ResponseEntity> GetDataObjects()
{
ResponseEntity response = new ResponseEntity();
var apiKey = "some-api-key";
var path = "path-to-external-service";
using (var client = new HttpClient())
{
var dataToProcess = // some data object
client.BaseAddress = new Uri(path);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync("", dataToProcess).ConfigureAwait(false);
string responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
var result = JsonConvert.DeserializeObject<ResponseEntity>(responseString);
return response;
}
}

How to call an async method?

I am not familiar with threading in .NET.
I have an ansync method MyTest:
public async Task MyTest() {
using (HttpClient httpClient = new HttpClient()) {
httpClient.BaseAddress = new Uri(_uri);
var response = await httpClient.GetAsync("API/GetData");
if(response!=null && response.IsSuccessStatusCode) {
var json = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
}
}
}
The problem that I am running into is calling the method to get the results (Dictionary).
When I step though my code I am seeing the IsCompleted is done before the results come back from my rest call.
How do I properly use threading in this case?
My method to call the async method.
public void GetTestData()
{
try
{
ARestService rest = new ARestService();
Task tsk = new Task(rest.MyTest);
if (tsk.IsCompleted)
{
var tst = "Done?";
}
}
catch(Exception ex)
{
string a = ex.Message;
}
}
If you can turn your GetTestData method into an async method simply do this.
public async Task GetTestData()
{
try
{
ARestService rest = new ARestService();
await rest.MyTest();
var tst = "Done?";
}
catch(Exception ex)
{
string a = ex.Message;
}
}
You should also define that your method returns a Task<Dictionary<string, string>> to receive the result of your rest service call, with the following statement.
Dictionary<string, string> dict = await rest.MyTest();
If not, have a look at some workarounds, like using GetAwaiter().GetResult() but as explained in this question Is .GetAwaiter().GetResult(); safe for general use? it can cause some problems, so the best option is to make your calling code async too.

Create generic async task function

I have created a function that returns an object using async/await. I would like to make the function generic so that it can return whatever object that I pass in. The code is boilerplate except for the objects being returned. I would like to be able to call GetAsync and have it return the correct object
public Patron getPatronById(string barcode)
{
string uri = "patrons/find?barcode=" + barcode;
Patron Patron = GetAsync(uri).Result;
return Patron;
}
private async Task<Patron> GetAsync(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
JavaScriptSerializer ser = new JavaScriptSerializer();
Patron Patron = ser.Deserialize<Patron>(content);
return Patron;
}
What about a generic method?
private async Task<T> GetAsync<T>(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
var serializer = new JavaScriptSerializer();
var t = serializer.Deserialize<T>(content);
return t;
}
Normally, you should place this method into another class and make it public, in order it can be used by methods in different classes.
Regarding the way you call this method, you could try the following:
// I capitalized the first letter of the method,
// since this is a very common convention in .NET
public Patron GetPatronById(string barcode)
{
string uri = "patrons/find?barcode=" + barcode;
var Patron = GetAsync<Patron>(uri).Result;
return Patron;
}
Note: In the above snippet I assumed that you haven't moved the GetAsync into another class. If you move it, then you have to make a slight change.
Update
I'm not following what you mean by your note. Do I need to make GetPatronById a task function as well - like Yuval has done below?
I mean something like this:
// The name of the class may be not the most suitable in this case.
public class Repo
{
public static async Task<T> GetAsync<T>(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
var serializer = new JavaScriptSerializer();
var t = serializer.Deserialize<T>(content);
return t;
}
}
public Patron GetPatronById(string barcode)
{
string uri = "patrons/find?barcode=" + barcode;
var Patron = Repo.GetAsync<Patron>(uri).Result;
return Patron;
}
Generic can be easily done with:
private async Task<T> GetAsync(string uri)
{
var client = GetHttpClient(uri);
var content = await client.GetStringAsync(uri);
return JsonConvert.DeserializeObject<T>(content);
}
Things to note:
JavaScriptSerializer has been deprecated for ages, avoid using it. Try out Json.NET instead.
This:
Patron Patron = GetAsync(uri).Result;
is dangerous and can cause potential deadlocks, especially in Web API. You need to go "async all the way":
public Task<Patron> GetPatronByIdAsync(string barcode)
{
string uri = $"patrons/find?barcode={barcode}";
return GetAsync<Patron>(uri);
}
And only your top most level invoker need await on the Task. Possibly some controller action:
public async Task SomeAction()
{
await GetPatronByIdAsync("hello");
}

Categories