How to call realtime streaming method from another class - c#

I need to centralize the calls to my realtime streaming Firebase database within a class, and call those methods from another class. The method is intended to 'listen' to the node within Firebase and then post to the application log upon updates.
However, my present setup notes it being synchronous and upon application run, returns null. How can I make this setup work?
TestFirebaseActions actions streaming class, method:
String output;
public async Task<String> realtimeStreamTest()
{
var observable = firebase
.Child("driver_rate")
.AsObservable<DriverRate>()
.Subscribe(d => output = d.Object.driversRate);
return output;
}
Calling method and attempting to "listen" from another class:
public async void firebaseRealStreamTestMethod()
{
TestFirebaseActions testFirebase = new TestFirebaseActions();
Task<String> contentsTask = testFirebase.realtimeStreamTest();
// await! control returns to the caller and the task continues to run on another thread
string contents = await contentsTask;
Log.Verbose("firebaseRealStreamTestMethod()", contents);
}
How can I create and call to allow for asynchronous listening on this observable from within another class?

Related

Trying to call async method - await vs GetAwaiter().GetResult();

I am trying to write a class with a method that will get some data from a REST API (the googleapi for youtube playlists) and dump that data into an ObservableCollection. The problem I am encountering is that when I call this:
this.getPlaylistItemsAsync().GetAwaiter().GetResult();
the code executes.
When I call this:
await this.getPlaylistItemsAsync();
it simply skips over the code.
I am pretty new to the whole asynchrounous programming thingy... I thikn I understand the basic concepts.. I just can't figure out how to do it :(
The full code is here:
#define DEBUG
//#define TestEnvi
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Newtonsoft.Json;
namespace IntuifaceYTPlaylist {
public class IFYT_Playlist {
public string playlistID {get;set;}= "PLYu7z3I8tdEmpjIoZHybXD4xmXXYrTqlk"; // The ID with which we identify our playlist
private string key = "supersecretAPIkey"; // The API-Key we use to access the google-API
public ObservableCollection<string> videosList {get;set;}= new ObservableCollection<string>();
public IFYT_Playlist () {
Console.WriteLine("Class Loaded!");
#if TestEnvi
this.getPlaylistItemsAsync().GetAwaiter().GetResult();
Console.WriteLine("This worked!");
await this.getPlaylistItemsAsync();
Console.WriteLine("This didn't!"); //In fact this line isn't even executed :(
#endif
}
#region getData
public async void update (){
this.getPlaylistItemsAsync().GetAwaiter().GetResult();
}
// Access the REST-API to retrieve the full dataset
// TODO: Manage connection to the API - DONE
// TODO: Parse JSON
public async Task<ObservableCollection<string>> getPlaylistItemsAsync(){
var output = new ObservableCollection<string>();
string URL = "https://www.googleapis.com/youtube/v3/playlistItems";
HttpClient client = new HttpClient();
string query = URL + "?key=" + this.key + "&part=contentDetails&playlistId=" + this.playlistID + "&maxResults=50";
var response = await client.GetStringAsync(query); //Dump the JSON string into an object!
# if DEBUG
// Dump the response into a file - just so we can check it if something goes wrong...
using (StreamWriter outputFile = new StreamWriter(Path.Combine("", "Dump.json")))
{
outputFile.WriteLine(response);
}
#endif
var responseData = JsonConvert.DeserializeObject<dynamic>(response);
// Iterate over the items in the list to get the VideoIDs of the individual videos
foreach (var item in responseData.items){
output.Add(JsonConvert.SerializeObject(item.contentDetails.videoId));
}
Console.WriteLine(output);
#if DEBUG //Let's see if that worked....
Console.WriteLine();
Console.WriteLine("Printing VideoIDs:");
Console.WriteLine();
foreach (var item in output){
Console.WriteLine(item);
}
Console.WriteLine();
#endif
this.videosList = output;
return output;
}
#endregion
}
}
The program I use to call this looks like this:
using System;
using IntuifaceYTPlaylist;
namespace TestEnvi
{
class Program
{
static void Main(string[] args)
{
Create();
}
static async void Create(){
IFYT_Playlist playlist = new IFYT_Playlist();
playlist.getPlaylistItemsAsync().GetAwaiter().GetResult();
Console.WriteLine("This worked!");
await playlist.getPlaylistItemsAsync();
Console.WriteLine("Did this?");
}
}
}
Invoked method immediately returns to the caller (i.e. to the Main) on first await and from there, both (the caller and the invoked method) run concurrently. Yet, since the Main finishes first, the whole program ends.
Thus, if you want to wait for asynchronous call completion you may change Create() to return Task rather than void and then you can wait such as: Create().Wait();
It's hard to tell from your code example, where exactly you're trying to update the list, because the code which you are pointing out to can't even be compiled. You can't use the await keyword in constructors, because constructors can't be async.
The main reason why you don't see console output is because your Main method doesn't wait for your async void Create to finish, because Create is async operation and as we know it's non blocking. Therefore your main thread just triggers the Create operation and continue doing other stuff below. But there is nothing below and that's it, the program is done.
To fix it, you should either turn your Main method to async method and call await Create(), or just call Create().Wait. You can also call Console.ReadLine if this is the console application.
By the way, it works with this.getPlaylistItemsAsync().GetAwaiter().GetResult();, because it's not asynchronous code any more, your Create method is blocked and it waits for the getPlaylistItemsAsync to finish. Similarly your Main method also waits for the Create to return, so that the program keep working.
You also have async void update method which you probably use somewhere (I don't know), so be careful with it since you don't have a way to know whether the method has finish its operation or not. Below is simplified explanation of asynchronous code in C# and why it might be bad to return void from the async method.
A bit about asynchronousy
The way how we can describe an asynchronous operations is that the operation is not blocking which means that you can tell that you want to begin the operation and continue doing other stuff not waiting the operation to finish its work. But this is not very useful to just start the operation (sometimes it might be useful), you usually want to do something when the operation is completed, failed etc. So in .NET the async operation returns Task or Task<T> which is the abstraction over the operation which might be completed or might be still in progress. Then you can attach your own code to be executed when a task is completed.
What happens under the hood when you await an operation
Keep in mind that this description is too simplified than what is actually happening.
So when you do something like this:
public async Task IFYT_Playlist () {
await this.getPlaylistItemsAsync();
... Do some other stuff when the `getPlaylistItemsAsync` has been completed
}
The IFYT_Playlist method attaches the code which is below await this.getPlaylistItemsAsync(); to the task which is returned by the method and return immediately. Again this is not what's actually happening, but can get you a basic idea:
public async Task IFYT_Playlist () {
Task resTask = this.getPlaylistItemsAsync();
return resTask.ContinueWith(t => ...Do some other stuff when the `getPlaylistItemsAsync` has been completed);
}
So that as it turned out async operation should return Task so that the caller will be able to attach a continuation to it (with ContinueWith) method. Do you see the problem now? If your return type is void, the caller won't be able to attach the code which should be executed when the operation has been completed. So, if getPlaylistItemsAsync's returns type is void, you can't await this.getPlaylistItemsAsync(), because it's impossible to call ContinueWith on nothing (void). Therefore you can't even have await with method that returns void.
public async Task IFYT_Playlist () {
await this.getPlaylistItemsAsync(); // doesn't compile
}
Therefore your update method should return Task or Task<T> for any suitable T in your case rather than nothing (void).

how can an async method be executed synchronously in Xamarin.Forms

I am building a screen for my app in xamarin.forms the caul is based on a tabbedpage which is built dynamically based on a list of objects which I get as a result of consuming a service.
After I call the method to consume the API that brings the list, I need to go through it based on certain data of it to fill an observable collection of viewmodels, which will be the tabs. The problem I have is that I do not know how to call the async method that consumes the API in a synchronized way so that the consumption of the API does not conflict with the operation of going through the list.
Then a fraction of the code of my ViewModel:
public MonitoringViewModel()
{
LoadThings();
Tabs = new ObservableCollection<MonitoringTabsViewModel>();
foreach (PcThing t in Things)
{
Tabs.Add(new MonitoringTabsViewModel(t.description));
}
}
private async void LoadThings()
{
Things = new List<PcThing>(await App.WebApiManager.GetCustomerThinksAsync());
}
What I get is that in xamarin live player the app after a few seconds go from the green signal to the red one without showing anything, and in the log of it I get this:
Target of GetEnumerator is null (NullReferenceException)
Since you are doing this in the constructor , I would try the following:
using System.Threading.Tasks;
The risk here is if you are not in control of the LoadThings completing, it can hang.
public MonitoringViewModel()
{
var task = Task.Run(async () => { await LoadThings();}
Task.WaitAll(task); //block and wait for task to complete
public async Task<List<PcThing>> LoadThings()
{
return await App.WebApiManager.GetCustomerThinksAsync();
}
And in your ViewModel
Things = LoadThings().GetAwaiter().GetResult();

wpf- How to wait for result from Dispatcher.invokeAsync before control is passed to next statement

I have a Lazy method in which I have called Dispacter
private Lazy<ObservableCollection<WidgetTasksSummary>> LazyTasksSummaryHelper()
{
return new Lazy<ObservableCollection<WidgetTasksSummary>>(() =>
{
Dispatcher.InvokeAsync(() => GetActivityItemsCount());
return new ObservableCollection<WidgetTasksSummary>(GetMyTasksSummary());
});
}
private ActivitySearchResultList ActivityItemsCount{get;set;}
private ObservableCollection<WidgetTasksSummary> GetMyTasksSummary()
{
//Do Something
}
private async Task GetActivityItemsCount()
{
try
{
ActivityItemsCount = await Ioc.Resolve<IServiceCall>().InvokeAsync<IActivityManager, ActivitySearchResultList>(this.MakeWeakFunc<IActivityManager, ActivitySearchResultList>((service) =>
service.GetActivityCounts(activityFilter)));
}
}
I am using ActivityItemsCount Property to assign result of api call.
After LazyTasksHelper is called, the control is sent to GetMyTasksSummary() after dispacter.
I want to wait for the dispacter to make api call and store result in property. And then continue execution.
I am using the property in getTasksSummary. So, I need it to be filled first in action called in dispacter then enter into method GetMyTasksSummary()
You need to change to AsyncLazy and await that call.
I found a solution. I moved all the api calls and other stuffs into another ViewModel and used Lazy<ViewModel>. In this way, viewmodel takes care of calling api and setting up necessary property.

Running multiple tasks asynchronously and awaiting for their results c#

In my service layer I wanted to fire multiple methods asynchronously and await for their results.
I tried with one at a time and it is erroring out.
In my service class I called the method like
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
And in DAL class the method definition looks like
public async Task<IEnumerable<ChapterCodeValidationOutput>> validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
Repository rep = new Repository();
if (!gmvi._chapterCodes.All(x => x.Equals("")))
{
var _validChapterCodes = await rep.ExecuteStoredProcedureAsync<Entities.Upload.ChapterCodeValidationOutput>(SQL.Upload.UploadValidation.getChapterCodeValidationSQL(gmvi._chapterCodes),null);
return _validChapterCodes;
}
else
return new List<ChapterCodeValidationOutput>();
}
Error message
Error 208 The await operator can only be used within an async method. Consider marking this method with the async modifier and changing its return type to Task<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>. C:\Users\m1034699\Desktop\Stuart_Upgrade_2.1_New Approach\Stuart_Export_Upload_v2.1\Stuart Web Service\ARC.Donor.Service\Upload\UploadValidationServices.cs 34 13 ARC.Donor.Service
in lines
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
What am I doing wrong ?
The error message is very explicit. It is telling you that you're Service class method is incorrectly attempting to use the async keyword. In order to fix this, you should be using "Async all the way" as defined in Stephen Cleary's post on MSDN as a best practice.
For example, if you're service class has a method body that is working with Task or Task<T>, or attempting to use the await keyword the method signature for this corresponding method body must be async (as the async keyword enables a method to use the await keyword). Additionally this method itself should also be Task or Task<T> returning, with very few exceptions to that rule.
Personally, I would alter your DAL class to simply return the operation that represents the asynchronous work without actually awaiting it. If you think about it, the body of the validateChapterCodeDetails method does not actually need to do anything with the results, it just needs to return them (instead of materializing them there). Consider the following:
public Task<IEnumerable<ChapterCodeValidationOutput>>
validateChapterCodeDetails(GroupMembershipValidationInput gmvi)
{
var rep = new Repository();
return gmvi._chapterCodes.All(x => x.Equals(""))
? new List<ChapterCodeValidationOutput>()
: rep.ExecuteStoredProcedureAsync
<Entities.Upload.ChapterCodeValidationOutput>
(SQL.Upload.UploadValidation
.getChapterCodeValidationSQL(gmvi._chapterCodes),null)
}
Since your Task<IEnumerable<ChapterCodeValidationOutput>> variable has already been awaited, you can access the .Result property to get what you're looking for.
Then in your Service class your method would look like this:
public async Task ConsumeAsync()
{
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = _validChapterCodesTask.Result;
// Do something with it...
}
Here is a .NET fiddle that should help to exemplify this for you better.
NOTE
I would also caution using IEnumerable as it pertains to your repo, you should ensure that the results from the Database are not occurring via deferred execution, otherwise you risk the potential for connection issues, i.e.; unintentionally leaving a connection open, or not properly closing one.
In the Service class where you call
var _validChapterCodesTask = gd.validateChapterCodeDetails(_input1);
await Task.WhenAll(_validChapterCodesTask);
var _chapterCodeResult = await _validChapterCodesTask;
add a async to the method signature where await Task.WhenAll(_validChapterCodesTask); is called. And when this method also has a return type you have to wrap this type in a Task like the exception shows:
Task<ARC.Donor.Business.Upload.GroupMembershipValidationOutput>
E.g. if you have the following method:
public GroupMemberShipValidationOutput validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}
You have to change the method signature to:
public async Task<GroupMemberShipValidationOutput> validate(..) {
...
await Task.WhenAll(_validChapterCodesTask);
...
}

Asynchronous task in asp .net MVC 5

I am trying to use async, await and task to implement one of an asynchronous requirement in my web application. I have below code in my controller class. What I want is that after the flow reaches to printing "controller 1", the system starts the business method on a separate thread and without waiting for the response system should reach to print statement in controller and print "controller 2". But when I am executing the below code I am getting output pattern as this-
controller 1
PlandesignBS
controller 2
Whereas I am expecting this-
controller 1
controller 2 (Flow should reach here immediately rather than waiting
for business methods to get executed First)
Contoller Class Code-
public class PlanDetailsController : Controller
{
[HttpPost]
public async Task<ActionResult> Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
//calls business method to generate
quoteId = await Task.Run(() => _planDesignBS.GenerateBS(planDetailsVM));
System.Diagnostics.Debug.WriteLine("controller 2");
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
}
Business Method Code-
public int GenerateBS(PandetailsDTO plandetails)
{
System.Diagnostics.Debug.WriteLine("PlandesignBS");
//STEP 1-> call to dataLogic Layer to use Entity Framework
// STEP 2-> call to a method (this method is part of dll used
//in our project and we don't have any control on it)
return quoteId
}
EDIT: The reason I am trying to do this is that I want to use few http Posts requests from my client side. Suppose I call the Generate action method first from my client side and then don't want to wait for the response of it and at the same time want to invoke another http post.
EDIT: Including EF code where I am getting execption when I am trying to follow few solutions.This method will be called from my GenerateBS method. I am getting exception on this line inside getSICCode method-
DbContext.Database.ExecuteSqlCommand("spGET_SICCode #industryClasifID,#industrySubClasifID,#SICCode OUTPUT", industryClasifID, industrySubClasifID, SICCode);
EF Code-
public class PlanDesignRepository : Repository<myobject>, IPlanDesignRepository
{
private IDbSet<myobject> _dbSet;
private DbContext _dbContext;
private IDbSet<myobject> DbSet
{
get
{
if (_dbSet == null)
{
_dbSet = base.UnitOfWork.Context.Set<myobject>();
}
return _dbSet;
}
}
private DbContext DbContext
{
get
{
if (_dbContext == null)
{
_dbContext = base.UnitOfWork.Context;
}
return _dbContext;
}
}
public string GetSICCode(IndustryClassficDO industryClassficDO)
{
SqlParameter industryClasifID = new SqlParameter("industryClasifID", SqlDbType.Int);
industryClasifID.Value = industryClassficDO.IndustryClassificationId;
SqlParameter industrySubClasifID = new SqlParameter("industrySubClasifID", SqlDbType.Int);
industrySubClasifID.Value = industryClassficDO.IndustrySubClassificationId;
SqlParameter SICCode = new SqlParameter("SICCode", SqlDbType.VarChar, 10);
SICCode.Direction = ParameterDirection.Output;
DbContext.Database.ExecuteSqlCommand("spGET_SICCode #industryClasifID,#industrySubClasifID,#SICCode OUTPUT", industryClasifID, industrySubClasifID, SICCode);
return (string)(SICCode.Value);
}
}
EDIT: I have few http Post calls as shown below-
AngularJS code for AJAX calls:
$http({
url: key_Url_Generate,
method: Post,
params: $scope.PlanDetails
}).then(function (result) {
//Notify user for success or failure
}
The usage of await means that you are waiting for the task to complete before continuing the code. If you want it to execute simultaneously with the other code you should change it like this
public class PlanDetailsController : Controller
{
[HttpPost]
public async Task<ActionResult> Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
//calls business method to generate
var task = Task.Run(() => _planDesignBS.GenerateBS(planDetailsVM));
System.Diagnostics.Debug.WriteLine("controller 2");
var quoteId = await task;
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
}
However I wouldn't recommend this as it serves no purpose and can degrade performance via starving the ASP.NET thread pool of threads. Why do you want to do this anyway?
This line:
quoteId = await Task.Run(() => _planDesignBS.GenerateBS(planDetailsVM));
asynchronously waits for the call inside Task.Run to complete. That's why you're seeing "PlandesignBS" printed and only after that you see the call to controller 2.
If you want to issue a "fire and forget" style of execution, you actually don't want to wait at all.
You should definitely not use Task.Run inside ASP.NET at all, as it's dangerous. Instead, if you're on .NET 4.5.2 and above, you can use HostingEnvironment.QueueBackgroundWorkItem or if not, you can use BackgroundTaskManager by Stephan Cleary, which safely registers the background thread with the application pool, so your thread doesn't get terminated once a re-cycle is invoked:
[HttpPost]
public ActionResult Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
HostingEnvironment.QueueBackgroundWorkItem(ct => _planDesignBS.GenerateBS(planDetailsVM));
System.Diagnostics.Debug.WriteLine("controller 2");
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
As a side note - If you're calling Entity Framework, there's usually no need to involve extra threads. Version 6 and above exposes TAP async based API's which are Task returning which you can use at your disposal for doing these kind of IO based queries.
The problem is, that you simply cannot dispatch asynchronous code that fall out of the asp.net request pipeline per se.
The async feature in asp.net MVC only improves the internal handling of threads inside the IIS process. It does NOT enable you to finish and close the response to the client, before all execution is completed.
If you want to do a real "fire-and-forget" solution, you need more than that.
I recently had the requirement that mails be sent asynchronously after a form in a web application has been submit.
The only way I found to solve this problem was to use hangfire:
http://hangfire.io/
Try this:
public class PlanDetailsController : Controller
{
[HttpPost]
public async Task<ActionResult> Generate(PlanDetailsVM planDetailsVM)
{
System.Diagnostics.Debug.WriteLine("controller 1");
//calls business method to generate
var quoteIdTask = GenerateAsyncBs();
System.Diagnostics.Debug.WriteLine("controller 2");
int id = await quoteIdTask;
return Json(quoteId , JsonRequestBehavior.AllowGet);
}
}
private async Task<int> GenerateBsAsync()
{
//do your planDetails logic here.
}

Categories