I'm working on an Xamarin.Forms application with MVVM. In my viewmodel I want to Get all the patients from an API. This is the code:
public async Task GetAllPatients()
{
try
{
isFetchingData = true;
var response = await httpClient.GetStringAsync(baseUrl + "/patient?query=ma");
var resultPatients =
JsonConvert.DeserializeObject<ObservableRangeCollection<PatientViewModel>>
(testJson,jsonSerializerSettings);
AllPatients.ReplaceRange(resultPatients);
Patients.ReplaceRange(resultPatients);
}
catch(Exception e)
{
Console.WriteLine("*****ERROR kon API niet ophalen");
Console.WriteLine(e.Message);
}
finally
{
CheckIfEmptyList();
isFetchingData = false;
}
}
At first I just got the API hard coded from a json string (testJson) in my code and everything went smoothly. But from the moment I put the htppClient out of commentary something strange happens (even when I don't use the variable as you can see in the code(I get the same result when I do use the variable though)).
The finally block is not executed.
It is to say, when I go and debug the app, the code goes through the finally and checks if the list is empty and puts isFetchingData to false. But I don't see that happening on the screen. If the list is empty a label should occur but now that label doesn't go away when list is not empty. The INotifyPropertyChanged does work good because without the httpClient it runs smoothly.
I'm very new to asynchronous programming so maybe I forgot to implement something that has to make sure the GetStringAsync ends properly? Maybe it keeps fetching the data and that is why I never see the finally block executed (even though it does behind the screen). I've read some articles about asynchronous programming but couldn't find something that could help me out.
I must also say that this method is called from the constructor, which makes it a little bit harder to run async. I tried calling it without async await and I tried calling it this way:
Task.Run(async ()=> { await GetAllPatients(); });
I tried with and without ConfigureAwait(false) but that doesn't make a difference either.
Finding a way to not put the method in the constructor (as suggested by CrowCoder and Albert) seemed the only possibility. In this case I managed to do so, but for other people it may not be always possible.
Because I work with MVVM without a framework and I'm very new to Xamarin and asynchronous programming (I'm a student), it was too difficult for me to find an alternative to the constructor.
I will put this as an answer, but if someone can give a code example where it would work to put the method in the constructor, or a workaround, it is still very welcome.
Related
I am integrating Google Firebase in Unity Game Engine using C#.
Here's my code:
FirebaseApp.DefaultInstance.SetEditorDatabaseUrl(databaseUrl);
var firebaseDatabase = FirebaseDatabase.DefaultInstance;
firebaseDatabase.GetReference("SomePath").GetValueAsync().ContinueWith(task =>{
HandleCallback(task.Result.ToDictionary());
});
void HandleCallback(dictionary<string,object> dic)
{
Debug.Log(dic.Keys.Count);
}
I need to somehow pass the result to another method to handle completion. I can't seem to get this to work.
here's no error, the log is just empty.
However if I call the Debug.Log(dic.Keys.Count) inside the Task it works.
Hope to learn and make this work.
Thank you.
Ok, this is strange, but I noticed if I manually create a dictionary from the result instead of using "ToDictionary()" the callback method is fired.
Hope it saves you time if you are having the same issue.
EDIT: I've edited a few lines of code, when running in the IDE it fails without an error or anything.
I'm new to Reactive Extensions and have a problem that I am trying to sort out. I'm using RX to queue events on a machine, then every so often send that data to a server. My problem appears to be that when the application is shutting down, anything that is an async call of any sort seems to just cancel and not run, thus the last batch of events never gets sent.
I have a Subject, where Event is my data class. I know now that a Subject might not be the best class to use, but here we are.
My code looks mostly like the following, added a few comments for clarity:
IObservable<IList<Event>> eventsObserver = Instance.EventBuffer.ToList<Event>();
var eventsEnumerable = eventsObserver.ToEnumerable();
List<Event> events = new List<Event>();
try
{
events = (List<Event>)eventsEnumerable.First(); // THIS LINE FAILS SILENTLY, EVEN IN DEBUGGER...
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine("Error: " + ex.Message);
}
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(someURI);
HttpResponseMessage response = client.PostAsync(somePage, new StringContent(SerializeToJSON(events))).Result;
response.EnsureSuccessStatusCode();
}
If I don't make the call to the web server synchronous (with the '.Result'), it fails there. I've tried a lot of ways to get the data from the IObservable into something I can send, but either the code fails (usually with a bad cast of some sort), or the events are not yet put into the data structure that I want to send. I know that RX is by nature async, and I'm asking to deal with it in a synchronous way, I would figure that there would be a solution. Thanks in advance!
Supposing that you control the Observable source, you could call Observable.OnComplete() like Enigmativity has pointed out. Otherwise, you could try to keep a copy of every value received before buffering it:
Observable.Do(x => localCopy = x).Buffer(..)
This local copy would be accessible to you at shutdown.
In any case, please note that .First() is marked obsolete in the latest Rx versions, possibly to avoid the problem you are experiencing.
Dilemma, dilemma...
I've been working up a solution to a problem that uses async calls to the HttpClient library (GetAsync=>ConfigureAwait(false) etc). IIn a console app, my dll is very responsive and the mixture of using the async await calls and the Parallel.ForEach(=>) really makes me glow.
Now for the issue. After moving from this test harness to the target app, things have become problematic. I'm using asp.net mvc 4 and have hit a few issues. The main issue really is that calling my process on a controller action actually blocks the main thread until the async actions are complete. I've tried using an async controller pattern, I've tried using Task.Factory, I've tried using new Threads. You name it, I've tried all the flavours - and then some!.
Now, I appreciate that the nature of http is not designed to facilitate long processes like this and there are a number of articles here on SO that say don't do it. However, there are mitigating reasons why i NEED to use this approach. The main reason that I need to run this in mvc is due to the fact that I actually update the live data cache (on the mvc app) in realtime via raising an event in my dll's code. This means that fragments of the 50-60 data feeds can be pushed out live before the entire async action is complete. Therefore, client apps can receive partial updates within seconds of the async action being instigated. If I were to delegate the process out to a console app that ran the entire process in the background, I'd no longer be able to harness those fragment partial updates and this is the raison d'etre behind the entire choice of this architecture.
Can anyone shed light on a solution that would allow me to mitigate the blocking of the thread, whilst at the same time, allow each async fragment to be consumed by my object model and fed out to the client apps (I'm using signalr to make these client updates). A kind of nirvanna would be a scenario where an out-of-process cache object could be shared between numerous processes - the cache update could then be triggered and consumed by my mvc process (aka - http://devproconnections.com/aspnet-mvc/out-process-caching-aspnet). And so back to reality...
I have also considered using a secondary webservice to achieve this, but would welcome other options before once again over engineering my solution (there are already many moving parts and a multitude of async Actions going on).
Sorry not to have added any code, I'm hoping for practical philosophy/insights, rather than code help on this, tho would of course welcome coded examples that illustrate a solution to my problem.
I'll update the question as we move in time, as my thinking process is still maturing on this.
[edit] - for the sake of clarity, the snippet below is my brothers grimm code collision (extracted from a larger body of work):
Parallel.ForEach(scrapeDataBases, new ParallelOptions()
{
MaxDegreeOfParallelism = Environment.ProcessorCount * 15
},
async dataBase =>
{
await dataBase.ScrapeUrlAsync().ConfigureAwait(false);
await UpdateData(dataType, (DataCheckerScrape)dataBase);
});
async and Parallel.ForEach do not mix naturally, so I'm not sure what your console solution looks like. Furthermore, Parallel should almost never be used on ASP.NET at all.
It sounds like what you would want is to just use Task.WhenAll.
On a side note, I think your reasoning around background processing on ASP.NET is incorrect. It is perfectly possible to have a separate process that updates the clients via SignalR.
Being that your question is pretty high level without a lot of code. You could try Reactive Extensions.
Something like
private IEnumerable<Task<Scraper>> ScrappedUrls()
{
// Return the 50 to 60 task for each website here.
// I assume they all return the same type.
// return .ScrapeUrlAsync().ConfigureAwait(false);
throw new NotImplementedException();
}
public async Task<IEnumerable<ScrapeOdds>> GetOdds()
{
var results = new Collection<ScrapeOdds>();
var urlRequest = ScrappedUrls();
var observerableUrls = urlRequest.Select(u => u.ToObservable()).Merge();
var publisher = observerableUrls.Publish();
var hubContext = GlobalHost.ConnectionManager.GetHubContext<OddsHub>();
publisher.Subscribe(scraper =>
{
// Whatever you do do convert to the result set
var scrapedOdds = scraper.GetOdds();
results.Add(scrapedOdds);
// update anything else you want when it arrives.
// Update SingalR here
hubContext.Clients.All.UpdatedOdds(scrapedOdds);
});
// Will fire off subscriptions and not continue until they are done.
await publisher;
return results;
}
The merge option will process the results as they come in. You can then update the signalR hubs plus whatever else you need to update as they come in. The controller action will have to wait for them all to come in. That's why there is an await on the publisher.
I don't really know if httpClient is going to like to have 50 - 60 web calls all at once or not. If it doesn't you can just take the IEnumerable to an array and break it down into a smaller chunks. And also there should be some error checking in there. With Rx you can also tell it to SubscribeOn and ObserverOn different threads but I think with everything being pretty much async that wouldn't be necessary.
Long post.. sorry
I've been reading up on this and tried back and forth with different solutions for a couple of days now but I can't find the most obvious choice for my predicament.
About my situation; I am presenting to the user a page that will contain a couple of different repeaters showing some info based on the result from a couple of webservice calls. I'd like to have the data brought in with an updatepanel (that would be querying the result table once per every two or three seconds until it found results) so I'd actually like to render the page and then when the data is "ready" it gets shown.
The page asks a controller for the info to render and the controller checks in a result table to see if there's anything to be found. If the specific data is not found it calls a method GetData() in WebServiceName.cs. GetData does not return anything but is supposed to start an async operation that gets the data from the webservice. The controller returns null and UpdatePanel waits for the next query.
When that operation is complete it'll store the data in it's relevant place in the db where the controller will find it the next time the page asks for it.
The solution I have in place now is to fire up another thread. I will host the page on a shared webserver and I don't know if this will cause any problems..
So the current code which resides on page.aspx:
Thread t = new Thread(new ThreadStart(CreateService));
t.Start();
}
void CreateService()
{
ServiceName serviceName = new ServiceName(user, "12345", "MOVING", "Apartment", "5100", "0", "72", "Bill", "rate_total", "1", "103", "serviceHost", "password");
}
At first I thought the solution was to use Begin[Method] and End[Method] but these don't seem to have been generated. I thought this seemed like a good solution so I was a little frustrated when they didn't show up.. is there a chance I might have missed a checkbox or something when adding the web references?
I do not want to use the [Method]Async since this stops the page from rendering until [Method]AsyncCompleted gets called from what I've understood.
The call I'm going to do is not CPU-intensive, I'm just waiting on a webService sitting on a slow server, so what I understood from this article: http://msdn.microsoft.com/en-us/magazine/cc164128.aspx making the threadpool bigger is not a choice as this will actually impair the performance instead (since I can't throw in a mountain of hardware).
What do you think is the best solution for my current situation? I don't really like the current one (only by gut feeling but anyway)
Thanks for reading this awfully long post..
Interesting. Until your question, I wasn't aware that VS changed from using Begin/End to Async/Completed when adding web references. I assumed that they would also include Begin/End, but apparently they did not.
You state "GetData does not return anything but is supposed to start an async operation that gets the data from the webservice," so I'm assuming that GetData actually blocks until the "async operation" completes. Otherwise, you could just call it synchronously.
Anyway, there are easy ways to get this working (asynchronous delegates, etc), but they consume a thread for each async operation, which doesn't scale.
You are correct that Async/Completed will block an asynchronous page. (side note: I believe that they will not block a synchronous page - but I've never tried that - so if you're using a non-async page, then you could try that). The method by which they "block" the asynchronous page is wrapped up in SynchronizationContext; in particular, each asynchronous page has a pending operation count which is incremented by Async and decremented after Completed.
You should be able to fake out this count (note: I haven't tried this either ;) ). Just substitute the default SynchronizationContext, which ignores the count:
var oldSyncContext = SynchronizationContext.Current;
try
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var serviceName = new ServiceName(..);
// Note: MyMethodCompleted will be invoked in a ThreadPool thread
// but WITHOUT an associated ASP.NET page, so some global state
// might be missing. Be careful with what code goes in there...
serviceName.MethodCompleted += MyMethodCompleted;
serviceName.MethodAsync(..);
}
finally
{
SynchronizationContext.SetSynchronizationContext(oldSyncContext);
}
I wrote a class that handles the temporary replacement of SynchronizationContext.Current as part of the Nito.Async library. Using that class simplifies the code to:
using (new ScopedSynchronizationContext(new SynchronizationContext()))
{
var serviceName = new ServiceName(..);
// Note: MyMethodCompleted will be invoked in a ThreadPool thread
// but WITHOUT an associated ASP.NET page, so some global state
// might be missing. Be careful with what code goes in there...
serviceName.MethodCompleted += MyMethodCompleted;
serviceName.MethodAsync(..);
}
This solution does not consume a thread that just waits for the operation to complete. It just registers a callback and keeps the connection open until the response arrives.
You can do this:
var action = new Action(CreateService);
action.BeginInvoke(action.EndInvoke, action);
or use ThreadPool.QueueUserWorkItem.
If using a Thread, make sure to set IsBackground=true.
There's a great post about fire and forget threads at http://consultingblogs.emc.com/jonathangeorge/archive/2009/09/10/make-methods-fire-and-forget-with-postsharp.aspx
try using below settings
[WebMethod]
[SoapDocumentMethod(OneWay = true)]
void MyAsyncMethod(parameters)
{
}
in your web service
but be careful if you use impersonation, we had problems on our side.
I'd encourage a different approach - one that doesn't use update panels. Update panels require an entire page to be loaded, and transferred over the wire - you only want the contents for a single control.
Consider doing a slightly more customized & optimized approach, using the MVC platform. Your data flow could look like:
Have the original request to your web page spawn a thread that goes out and warms your data.
Have a "skeleton" page returned to your client
In said page, have a javascript thread that calls your server asking for the data.
Using MVC, have a controller action that returns a partial view, which is limited to just the control you're interested in.
This will reduce your server load (can have a backoff algorithm), reduce the amount of info sent over the wire, and still give a great experience to the client.
in playing around with the idea of using a webservice for my project I noticed that a couple of properties ( method/event ) were automatically created for me. I can see the purpose of the Completed event but I am not sure where the Async method would be used.
webmethod declaration:
[WebMethod]
public string HelloBrad()
{
return "Hello Brad";
}
Consumption of service in codebehind
localhost.Service1 service = new localhost.Service1();;
service.HelloBradAsync
service.HelloBradCompleted
service.HelloBrad
could somebody please explain the usage of the HelloBradAsync method.
Thanks
Async methodology allows your code to continue executing while the server is processing the message. Using your normal service.HelloBrad code, the thread will block until the webservices returns a response.
Instead, if you call HelloBradAsync, it immediately moves on to your next line of code. When the server is done, it will respond inside the "HelloBradCompleted" event.
This is so that the webservice doesn't block your primary thread while it executes, and is definitely the proper way of doing business. It might require a change in your programming paradigm, but you'll find the benefits outweigh the costs.