I am starting to create some classes who will fire asynchronous operations and I want the client to register a callback to receive some results. Finally I reached the following code. It is just an example, and I would like to know if there is a better way of doing it using TaskFactory and Action<>, Func<>
Here is the client basic example:
Client client2 = new Client();
client2.GetClientList(ClientCallBack);
private static void ClientCallBack(List<Client> listado)
{
//Receive the list result and do some stuff in UI
}
Here is the Client class GetCLientList asynchronous example:
public void GetClientList(Action<List<Client>> Callback)
{
List<Client> listado=null;
Task.Factory.StartNew(() =>
{
listado = new List<Client>{
new Client{ apellidos="Landeras",nombre="Carlos",edad=25},
new Client{ apellidos="Lopez", nombre="Pepe", edad=22},
new Client{ apellidos="Estevez", nombre="Alberto", edad=28}
};
//Thread.Sleep to simulate some load
System.Threading.Thread.Sleep(4000);
}).ContinueWith((prevTask) =>
{
Callback(listado);
}
);
}
Is there a better way of doing it?. I know I can return Task from my function and register the continueWith in client side, but I want to wrap it inside the class.
EDIT
I'm posting another example. I was trying to make sync/async versions of a webrequest.
Is this approach correct?:
public string ExecuteRequest(string url)
{
HttpWebRequest httpwebrequest = (HttpWebRequest) WebRequest.Create(url);
HttpWebResponse httpwebresponse = (HttpWebResponse) httpwebrequest.GetResponse();
using (StreamReader sr = new StreamReader(httpwebresponse.GetResponseStream()))
{
return sr.ReadToEnd();
}
}
public void ExecuteRequestAsync(string uri,Action<string> callbackResult)
{
Task.Factory.StartNew(() => ExecuteRequest(uri), CancellationToken.None)
.ContinueWith((task) => callbackResult(task.Result));
}
First, your method doesn't seem to be actually asynchronous, so you're not going to gain much from making it look like one. If the user of your method decides to run it on another thread, they can do it themselves.
Second, if you can use C# 5.0, you should follow the Task-based asynchronous pattern, to make your method easier to use. With that (and assuming you have a reason to ignore my first point above), your code could look like this:
public Task<List<Client>> GetClientListAsync()
{
return Task.Run(() =>
{
var list = new List<Client>
{
new Client { apellidos="Landeras", nombre="Carlos", edad=25 },
new Client { apellidos="Lopez", nombre="Pepe", edad=22 },
new Client { apellidos="Estevez", nombre="Alberto", edad=28 }
};
//Thread.Sleep to simulate some load
System.Threading.Thread.Sleep(4000);
return list;
});
}
Or, if you wanted to make your code actually asynchronous:
public async Task<List<Client>> GetClientListAsync()
{
var list = new List<Client>
{
new Client { apellidos="Landeras", nombre="Carlos", edad=25 },
new Client { apellidos="Lopez", nombre="Pepe", edad=22 },
new Client { apellidos="Estevez", nombre="Alberto", edad=28 }
};
//Task.Delay() to simulate some load
await Task.Delay(4000);
return list;
}
In both cases, you could then use this method without using callbacks from an async method like this:
var client = new Client();
var list = await client.GetClientListAsync();
//Receive the list result and do some stuff in UI
Third, if you didn't want to (or couldn't) use async-await, then your code is close, but quite right. The problem is that the callback won't actually execute on the UI thread. For that, you would need to use TaskScheduler.FromCurrentSynchronizationContext().
Also, your design where Client has a GetClientList() method seems suspicious to me. Such method probably belongs to some sort of repository object, not to Client.
Related
This question already has answers here:
Can constructors be async?
(15 answers)
Closed 25 days ago.
I've read many explanations but none of them made sense to me.
I'm doing this in Xamarin.Forms:
public class SomeClass
{
public SomeClass
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = Task.Run<Location>(async () => await Geolocation.GetLocationAsync(request, cts.Token));
var userLat = location.Latitude; // doesn't work
var userLon = location.Longitude; // doesn't work
}
}
The reason I'm doing this is that I'm trying to load all the methods I need such as getting the user's location, show it on the map, load up some pins etc. as soon as the Xamarin.Forms.Maps map appears.
I know it's bad practice from what you guys answered so I'm working on changing that but I'm still having a hard time understanding how to do it differently in the sense of it's confusing. But I'm reading your articles and links to make sure I understand.
I tried to run Task.Run(async () => await) on many methods, and tried to save their values in variables but I can't get the returned value and that's what made me post this question, I need to change my code.
I know could get the returned value using Task.Result() but I've read that this was bad.
How to get the UI to load and wait on the ViewModel to do what it has to do, and then tell the UI to then use whatever the ViewModel is giving him when it is ready ?
You mentioned in a comment to another answer that you can't do it async because this code is in a constructor. In that case, it is recommended to move the asynchronous code into a separate method:
public class MyClass
{
public async Task Init()
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
var userLat = location.Latitude;
var userLon = location.Longitude;
}
}
You can use it the following way:
var myObject = new MyClass();
await myObject.Init();
The other methods of this class could throw an InvalidOperationException if Init() wasn't called yet. You can set a private boolean variable wasInitialized to true at the end of the Init() method. As an alternative, you can make your constructor private an create a static method that creates your object. By this, you can assure that your object is always initialized correctly:
public class MyClass
{
private MyClass() { }
public async Task<MyClass> CreateNewMyClass()
{
var result = new MyClass();
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
result.userLat = location.Latitude;
result.userLon = location.Longitude;
return result;
}
}
I think it could be this:
public async Task SomeMethodAsync()
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = await Geolocation.GetLocationAsync(request, cts.Token);
var userLat = location.Latitude;
var userLon = location.Longitude;
}
Not that methods which contain await calls should be marked as async. If you need to return something from this method then the return type will be Task<TResult>.
Constructors cannot be marked with async keyword. And it's better not to call any async methods from constructor, because it cannot be done the right way with await. As an alternative please consider Factory Method pattern. Check the following article of Stephen Cleary for details: Async OOP 2: Constructors.
The normal way to retrieve results from a Task<T> is to use await. However, since this is a constructor, there are some additional wrinkles.
Think of it this way: asynchronous code make take some time to complete, and you can never be sure how long. This is in conflict with the UI requirements; when Xamarin creates your UI, it needs something to show the user right now.
So, your UI class constructor must complete synchronously. The normal way to handle this is to (immediately and synchronously) create the UI in some kind of "loading..." state and start the asynchronous operation. Then, when the operation completes, update the UI with that data.
I discuss this in more detail in my article on async data binding.
Do the asynchronous work before constructing the object and pass in the data to the constructor. I suggest a factory.
class MyFactory : IMyFactory
{
public async Task<MyClass> GetMyClass()
{
var request = new GeolocationRequest(GeolocationAccuracy.High, TimeSpan.FromSeconds(10));
var cts = new CancellationTokenSource();
var location = Task.Run<Location>(async () => await Geolocation.GetLocationAsync(request, cts.Token));
return new MyClass(location);
}
}
class MyClass
{
public MyClass(Location location)
{
var userLat = location.Latitude;
var userLon = location.Longitude;
//etc....
}
}
To create an instance, instead of
var x = new MyClass();
you'd call
var factory = new MyFactory();
var x = await factory.GetMyClass();
The nice thing about this approach is that you can mock the factory (e.g. for unit tests) in a way that does not depend on the external service.
I have an API in c# (MYAPI) which takes a request, and makes an API call to Unity (UNITYAPI) to perform some action.
The flow should be like this
Client -> MYAPI -> UnityAPI -> performs task -> response from UnityAPI to MYAPI -> response to client.
Now, A client can call MYAPI through different threads. MYAPI should wait for the previous MYAPI calls to complete (which in turn means that the UNITYAPI completed some action). MYAPI "CANNOT" send any request to UNITYAPI until the previous calls of MYAPI are responed back to the client.
Function in MYAPI to make api calls to UNITY API:
static async Task<string> PostURI(HttpContent c)
{
Uri uri = new Uri("http://localhost:4444");
var response = string.Empty;
using (var client = new HttpClient())
{
HttpResponseMessage result = null;
try
{
result = await client.PostAsync(uri, c);
}
catch (Exception ex)
{
throw ex;
}
if (result.IsSuccessStatusCode)
{
response = result.StatusCode.ToString();
}
}
return response;
}
Function in MYAPI which handles all the calls:
public void ProcessCalls(string operation)
{
HttpContent next = new StringContent(operation);
while (isBlocked == true)
{
}
isBlocked = true;
var t = Task.Run(() => PostURI(next));
t.Wait();
isBlocked = false;
}
Here, you can see the workaround I did. I just used a static variable isBlocked to make any call wait in an infinite while loop until any other operation is being done.
This works fine when I send 2 parallel calls to MYAPI. The second call waits for the first to complete, then proceeds to send call to UNITYAPI and waits. But when I send 3 calls in parallel, it breaks. The first call completes in unity but no response is received for any call. There must be an elegant way to do this.
So what i want is:
-The client should be able to send multiple requests to MYAPI.
-Each request should be made to wait till ALL the previous requests have sent a response back to client.
Thanks in advance.
EDIT 1: The method which calls ProcessCalls:
[HttpPost]
[Route("MyPostRoute")]
public async void MyPostRoute()
{
var request = new StreamReader(Request.Body).ReadToEnd();
// Doing some validations on the request
if (request.isValid())
{
await helperobject.ProcessCalls(request);
//helperobject is an object of the class which has the two functions mentioned above.
}
else
throw new Exception("Input was not in Correct format");
}
Using a Semaphore, you need to make it static, so all instances of that class use the same one. Then you can go like this:
private static SemaphoreSlim processCallsSemaphore = new SemaphoreSlim(1,1);
// new SemaphoreSlim(1,1); => start with 1 count available and allow at max 1.
public async Task ProcessCalls(string operation)
{
HttpContent next = new StringContent(operation);
try
{
await processCallsSemaphore.WaitAsync();
await PostURI(next); // Assuming this is also an async API or can be made one.
}
finally
{
processCallsSemaphore.Release();
}
}
I have a challenge, I need to call many http request and handle each of them.
How to do it, I don't want to wait for get response from one of them and then call next, how to assign a method for process response (like callback).
How can define callback and assign to each of them ?
What you need is an Asynchronous programming model where you create async tasks and later use await keyword for the response.
So essentially you are not waiting for the first async call to finish, you'd just fire as many async tasks as you wish and wait to get a response only when you need the response to move ahead with your program logic.
Have a look at below for more details:
https://msdn.microsoft.com/en-us/library/hh696703.aspx
1) you can call that normaly(noneasync):
public string TestNoneAsync()
{
var webClient = new WebClient();
return webClient.DownloadString("http://www.google.com");
}
2) you can use APM (async):
private void SpecAPI()
{
var req = (HttpWebRequest)WebRequest.Create("http://www.google.com");
//req.Method = "HEAD";
req.BeginGetResponse(
asyncResult =>
{
var resp = (HttpWebResponse)req.EndGetResponse(asyncResult);
var headersText = formatHeaders(resp.Headers);
Console.WriteLine(headersText);
}, null);
}
private string formatHeaders(WebHeaderCollection headers)
{
var headerString = headers.Keys.Cast<string>()
.Select(header => string.Format("{0}:{1}", header, headers[header]));
return string.Join(Environment.NewLine, headerString.ToArray());
}
3) you can create a callback and asign it,EAP.(async .net 2):
public void EAPAsync()
{
var webClient = new WebClient();
webClient.DownloadStringAsync(new Uri("http://www.google.com"));
webClient.DownloadStringCompleted += webClientDownloadStringCompleted;
}
void webClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
// use e.Result
Console.WriteLine("download completed callback.");
}
4) you can use newer way TAP, cleare way (c# 5). it's recommended:
public async Task<string> DownloadAsync(string url)
{
var webClient = new WebClient();
return await webClient.DownloadStringTaskAsync(url);
}
public void DownloadAsyncHandler()
{
//DownloadAsync("http://www.google.com");
}
threading in this solution is't good approch.(many threads that pending to call http request!)
I know it has been asked a lot, but my problem is, that my method won't wait for the request to be completet, even though i have implemented a TaskCompletionSource, which should have done the job, but it doesn't.
public DecksViewModel(bool local)
{
DList = new List<Deck>();
if (local)
InitializeLocalDeckList();
else
{
Dereffering();
}
}
public async void Dereffering()
{
var e = await InitilaizeWebDeckList();
List<DeckIn> decksIn = JsonConvert.DeserializeObject<List<DeckIn>>(e);
foreach (DeckIn d in decksIn)
{
Deck dadd = new Deck();
dadd.CardCount = 0;
dadd.Name = d.name;
dadd.PicturePath = d.image;
dadd.InstallDirectory = false;
DList.Add(dadd);
}
DataSource = AlphaKeyGroup<Deck>.CreateGroups(DList, System.Threading.Thread.CurrentThread.CurrentUICulture, (Deck s) => { return s.Name; }, true);
}
public Task<String> InitilaizeWebDeckList()
{
var tcs = new TaskCompletionSource<string>();
var client = new RestClient("blabla.com");
var request = new RestRequest("");
request.AddHeader("Authorization", "Basic blabla");
client.ExecuteAsync(request, response =>
{
test = response.Content;
tcs.SetResult(response.Content);
});
return tcs.Task;
}
So when I call the DecksViewModel constructor, I asyncally try to request the data from a webserver and fill the model.
The point is, that the corresponding view "doesn't wait" for the request to fill the model, so it's displayed empty.
I use the
List<AlphaKeyGroup<Deck>> DataSource
to fill a LongListSelector via DataBinding. But DataSource isn't yet set, when it is binded.
I hope you can help
You're calling an async method without awaiting it inside the constructor. That's why "it doesn't wait" (because it has nothing to wait on).
It's usually a bad idea to call an async method inside the constructor for that reason combined with the fact that constructors can't be async.
You should redesign your solution accordingly. An option is to have an async static method that creates an instance and awaits the procedure:
public static async Task CreateInstance(bool local)
{
var model = new DecksViewModel();
if (local)
{
await InitializeLocalDeckList();
}
else
{
await Dereffering();
}
}
That would allow you to not use async void which should only be used in UI even handlers.
You can read more about other options in Stephen Cleary's blog
You are using async void, which means nobody's gonna wait for that. It's just fire and forget.
I see some misunderstanding in the async keyword here:
Your code will only wait for the result of an async method, if you use await. Otherwise that call will just start the async method, but you don't know when it is actually gonna run.
You cannot use await in constructors though.
I've been struggling with async / await for a week now. Some background: the code below is part of an MVC4 website project. The website has a large number of API calls happening. The goal is to get those API calls happening in parallel instead of synchronous to improve site responsiveness. Right now all the API calls block each other. So if one page requires 4 calls...longer load time.
I've built out individual methods for both the synchronous and async versions of all the API calls. The problem I have is the await never responds. I think it's related to this question. However, I'm really not sure how to solve it. I've tried the ConfigureAwait(false), and that hasn't helped me.
Here's the code:
The initial call in the controller it looks like so:
BaseData bdata = API.GetBaseData().Result;
I'd love to use await here, but that's not an option without an AsyncController, which we can't use due to needing request / response access. The other methods are in the API class:
internal static async Task<BaseData> GetBaseData() {
var catTask = GetParentCategoriesAsync();
var yearTask = GetYearsAsync();
await Task.WhenAll(new Task[] { catTask, yearTask });
var bdata = new BaseData {
years = await yearTask,
cats = await catTask
};
return bdata;
}
internal static async Task<List<APICategory>> GetParentCategoriesAsync() {
try {
WebClient wc = new WebClient();
wc.Proxy = null;
string url = getAPIPath();
url += "GetFullParentCategories";
url += "?dataType=JSON";
Uri targeturi = new Uri(url);
List<APICategory> cats = new List<APICategory>();
var cat_json = await wc.DownloadStringTaskAsync(targeturi);
cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json);
return cats;
} catch (Exception) {
return new List<APICategory>();
}
}
internal static async Task<List<double>> GetYearsAsync() {
WebClient wc = new WebClient();
wc.Proxy = null;
Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON");
var year_json = await wc.DownloadStringTaskAsync(targeturi);
List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json);
return years;
}
When these methods are called, I can put breakpoints in GetYearsAsync() and GetParentCategoriesAsync(). Everything fires until the await wc.DownloadStringTaskAsync(targeturi) command. That's where stops.
I've added ConfigureAwait(continueOnCapturedContext: false) to all the tasks, but that hasn't helped. I'm assuming the problem is that the threads are not in the same context. However, I'm not certain. I am certain, however, that I'm doing something wrong. I'm just not sure what. It's either that or I'm just trying to do something that can't be done with .NET MVC4. Any thoughts would be supremely appreciated.
The problem is actually due to WebClient, which will always sync back to the request context (which is blocked due to the Result call).
You can use HttpClient instead, combined with ConfigureAwait(false):
internal static async Task<BaseData> GetBaseDataAsync() {
var catTask = GetParentCategoriesAsync();
var yearTask = GetYearsAsync();
await Task.WhenAll(catTask, yearTask).ConfigureAwait(false);
var bdata = new BaseData {
years = await yearTask,
cats = await catTask
};
return bdata;
}
internal static async Task<List<APICategory>> GetParentCategoriesAsync() {
try {
var client = new HttpClient();
string url = getAPIPath();
url += "GetFullParentCategories";
url += "?dataType=JSON";
Uri targeturi = new Uri(url);
List<APICategory> cats = new List<APICategory>();
var cat_json = await client.GetStringAsync(targeturi).ConfigureAwait(false);
cats = JsonConvert.DeserializeObject<List<APICategory>>(cat_json);
return cats;
} catch (Exception) {
return new List<APICategory>();
}
}
internal static async Task<List<double>> GetYearsAsync() {
var client = new HttpClient();
Uri targeturi = new Uri(getAPIPath() + "getyear?dataType=JSON");
var year_json = await client.GetStringAsync(targeturi).ConfigureAwait(false);
List<double> years = JsonConvert.DeserializeObject<List<double>>(year_json);
return years;
}
That should enable you to call it as such:
BaseData bdata = API.GetBaseDataAsync().Result;
However, I strongly recommend that you call it as such:
BaseData bdata = await API.GetBaseDataAsync();
You'll find that the code both before and after the await can access the request and response context just fine.
I ended up following a combination of Servy's and Stephen Cleary's advice. Based on Stephen's response, I realized I could access the request/response as long as I did it before I made any asynchronous calls in the controller.
If I stored the HttpContext in a variable, I could pass that context around to any model/service method that needed access to it. This allowed me to just go async all the way up like Servy suggested. After that, I had no issues with anything I wanted with the async patterns.