I'm having this issue that I've been going crazy over for a few hours now. I've got a table stored in Azure that holds tasks a user wants to accomplish. Each task has a status which can be an integer value of either 1, 2 or 3 corresponding to to do, in progress or completed respectively. I'm trying to create three separate gauges which tell the user how many tasks they have in each of those three categories, but everything I've tried throws a MobileServiceInvalidOperation error and I can't seem to figure out why.
--EDIT--
I was getting a similar issue in another part of my program, and the issue turned out to be one of permissions. Once I included the user authentication code that I had used on another page, the queries I was running on that page started to work. Including that code however, did not stop this exception from being thrown on the code below. I now think that the issue has to do with this code running before the app authenticates the user. If this is the case, how would I go about making sure this code runs after the authentication code does?
--END EDIT--
I'll list out some of my attempts below:
private MobileServiceCollection<SbTask, SbTask> taskItems;
private IMobileServiceTable<SbTask> taskTable = App.MobileService.GetTable<SbTask>();
Attempt 1)
private async void GetTodo()
{
// Can't convert IMobileServiceTableQuery<Int> to
// IMobileServiceQuery<AppName.Models.Sbtask>
IMobileServiceTableQuery<SbTask> query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status);
}
Attempt 2)
private async void GetTodo()
{
IMobileServiceTableQuery<int> query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status);
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
List<int> statusOne = await query.ToListAsync();
Value = statusOne.Count; // Also tried statusOne.Sum();
}
Attempt 3)
private async void GetTodo()
{
var query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status)
.IncludeTotalCount();
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
var results = await query.ToEnumerableAsync();
long count = ((ItotalCountProvider)results).TotalCount;
int counts = Int32.Parse(count.ToString());
List<int> stats = await query.ToListAsync();
for (int i = 0; i < counts; i++)
{
Value += stats[i];
}
}
Attempt 4)
private async void GetTodo()
{
var query = taskTable
.Where(t => t.Status == 1)
.Select(t => t.Status)
.IncludeTotalCount();
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
List<int> stats = await query.ToListAsync();
long count = ((ItotalCountProvider)stats).TotalCount;
int counts = Int32.Parse(count.ToString());
for (int i = 0; i < counts; i++)
{
Value += stats[i];
}
}
Attempt 5)
private async void GetTodo()
{
// MobileServiceInvalidOperationException
// Additional information: Error: Unauthorized
taskItems = await taskTable.ToCollectionAsync();
Value = taskItems.Count(t => t.Status == 1);
}
I've tried a couple of other things that probably aren't even worth mentioning, and I've been searching all over for solutions to this problem--all's I've really learned is that this is a difficult problem and I (obviously) haven't really found a solution.
Thanks in advance to anyone who can help.
So it turns out that the issue was related to authentication. Moving the GetTodo() method out of my viewmodel class and into the xaml.cs file did the trick.
Related
I'm building a game in Unity version 2019.4.1f1 (LTS) and i'm using Firebase Firestore database.
Basically when I try to fetch the user from the database, specifically when i'm calling GetSnapshotAsync(), it gets stuck.
The hierarchy is as follows:
StartState calls FetchUserState which calls DBGetObjectState which communicates with DatabaseManager (DatabaseManager contains the line where GetSnapshotAsync() gets called).
Would be really nice if someone could help me figure out this problem.
Thank you for helping!
class FetchUserState
//fetch user by userId
await stateManager.PushTempState(new DBGetObjectState<T>(StringConstants.DB_USERS_COLLECTION, //("Users")
field: "UserId", fieldEqualTo: _userId, withLoading: false));
class DBGetObjectState
Log("Getting Documents");
var documents = await DatabaseManager.GetDocuments<T>(_path, _limit, _orderBy, _orderByDescending, _field, _fieldEqualTo);
Log("Got something, checking..."); // doesn't get here
class DatabaseManager
public static async Task<Collection<T>> GetDocuments<T>(string path, int limit = -1,
string orderBy = null, string orderByDescending = null, string field = null, object fieldEqualTo = null)
{
var collectionRef = DBUtills.GetCollectionRef(path);
Query query = collectionRef;
if (field != null && fieldEqualTo != null)
query = query.WhereEqualTo(field, fieldEqualTo);
if (orderBy != null)
query = query.OrderBy(orderBy);
if (orderByDescending != null)
query = query.OrderByDescending(orderByDescending);
if (limit >= 0)
query = query.Limit(limit);
Debug.Log("Snapshotting!");
QuerySnapshot collectionSnapshot = await query.GetSnapshotAsync();
Debug.Log("got a snapshot, checking..."); // doesn't get here
//....
}
Thanks to anyone who tried to help, apparently it was a plugin that I used for handling tasks, I should've checked it first before even asking the question.
Anyways, if someone still experiences an issue, #derHugo's answer was definitely a solution, instead of awaiting the task, simply use ContinueWithOnMainThread() to create a callback that will be called after the task is finished, like that:
query.GetSnapshotAsync().ContinueWithOnMainThread(task =>
{
if(task.IsFaulted)
{
//....
}
QuerySnapshot collectionSnapshot = task.Result;
//....
}
Consider the following method:
public async Task<IEnumerable<TORTDTransmissionOwner>> ReturnActiveTransmissionOwnersForUser(User inputUser)
{
_logger.LogDebug("ReturnActiveTransmissionOwnersForUser executing with user: {0}", inputUser.Email);
IEnumerable<TORTDTransmissionOwner> transmissionOwners;
if (inputUser.IsAdmin || inputUser.IsApprover)
{
transmissionOwners = await _toStakeholderUploadDataService.GetTORTDTransmissionOwners();
_logger.LogDebug("User isAdmin or isApprover, count of TOs: {0}", transmissionOwners.Count());
}
else
{
transmissionOwners = inputUser.TransmissionOwners.Where(to => to.IsImplemented)
.OrderBy(to => to.TORTDTransmissionOwner.Dbaname).Select(to => to.TORTDTransmissionOwner);
_logger.LogDebug("User is standard, count of TOs: {0}", transmissionOwners.Count());
}
return transmissionOwners;
}
Currently, ReSharper is giving me a warning that I will be causing multiple enumerations of the results from what is a database call.
But, if I change the database call to be like:
public Task<IEnumerable<TORTDTransmissionOwner>> ReturnActiveTransmissionOwnersForUser(User inputUser)
{
_logger.LogDebug("ReturnActiveTransmissionOwnersForUser executing with user: {0}", inputUser.Email);
IEnumerable<TORTDTransmissionOwner> transmissionOwners;
if (inputUser.IsAdmin || inputUser.IsApprover)
{
transmissionOwners = _toStakeholderUploadDataService.GetTORTDTransmissionOwners().Result.ToList();
_logger.LogDebug("User isAdmin or isApprover, count of TOs: {0}", transmissionOwners.Count());
}
else
{
transmissionOwners = inputUser.TransmissionOwners.Where(to => to.IsImplemented)
.OrderBy(to => to.TORTDTransmissionOwner.Dbaname).Select(to => to.TORTDTransmissionOwner).ToList();
_logger.LogDebug("User is standard, count of TOs: {0}", transmissionOwners.Count());
}
return transmissionOwners;
}
I've lost the need for Async and forced every database call to be syncronous. When I am not using debug logging, I would rather have async, right?
So my question is, how do I choose the right approach here? Or is there a way to write this method better so that I can have both async and my debug statements if and when I need?
You can also materialize after the async call returns:
transmissionOwners =
(await _toStakeholderUploadDataService.GetTORTDTransmissionOwners()).ToList();
So we have an .NET Core API which uses hangfire as a task scheduler.
On startup, our API starts the following functions :
public void CreateTasks()
{
/* DATABASE TASKS */
SyncDatabaseTask();
/* SMS TASKS */
SendSmsTask();
}
public void SendSmsTask()
{
var taskId = BackgroundJob.Schedule(() => _smsService.SendSms(), TimeSpan.FromMinutes(30));
BackgroundJob.ContinueWith(taskId, () => SendSmsTask());
}
This creates the job SendSmsTask in Hangfire on startup and does not start a second job until the first one has been completed.
The issue that we just noticed however is that whenever our API reboots (server update for example) the existing jobs are still running and news jobs are being added.
So we would like to remove all scheduled or running jobs on startup.
I've looked through the documentation (http://docs.hangfire.io/en/latest/) but couldn't really find a solution for this issue.
This should solve your problem, just note that this is untested.
private void RemoveAllHangfireJobs()
{
var hangfireMonitor = JobStorage.Current.GetMonitoringApi();
//RecurringJobs
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => BackgroundJob.Delete(xx.Id));
//ProcessingJobs
hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//ScheduledJobs
hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//EnqueuedJobs
hangfireMonitor.Queues().ToList().ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name,0, int.MaxValue).ForEach(x => BackgroundJob.Delete(x.Key)));
}
If you still interest Pieter Alberts solution.
Some little changes on that.
If you use old code and you have old job in db, you will get Format Exception.
In //RecurringJobs section you have to change line like this:
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => RecurringJob.RemoveIfExists(xx.Id));
TL;DR
Old Code:
private void RemoveAllHangfireJobs()
{
var hangfireMonitor = JobStorage.Current.GetMonitoringApi();
//RecurringJobs
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => BackgroundJob.Delete(xx.Id));
//ProcessingJobs
hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//ScheduledJobs
hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//EnqueuedJobs
hangfireMonitor.Queues().ToList().ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name,0, int.MaxValue).ForEach(x => BackgroundJob.Delete(x.Key)));
}
New Code:
private void RemoveAllHangfireJobs()
{
var hangfireMonitor = JobStorage.Current.GetMonitoringApi();
//RecurringJobs
JobStorage.Current.GetConnection().GetRecurringJobs().ForEach(xx => RecurringJob.RemoveIfExists(xx.Id)); // this line changed!
//ProcessingJobs
hangfireMonitor.ProcessingJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//ScheduledJobs
hangfireMonitor.ScheduledJobs(0, int.MaxValue).ForEach(xx => BackgroundJob.Delete(xx.Key));
//EnqueuedJobs
hangfireMonitor.Queues().ToList().ForEach(xx => hangfireMonitor.EnqueuedJobs(xx.Name,0, int.MaxValue).ForEach(x => BackgroundJob.Delete(x.Key)));
}
PS Edit:
My Hangfire version is 1.7.9
and using Hangfire.PostgreSql
//Start Hangfire Server
var varJobOptions = new BackgroundJobServerOptions();
varJobOptions.ServerName = "job.fiscal.io";
varJobOptions.WorkerCount = Environment.ProcessorCount * 10;
app.UseHangfireServer(varJobOptions);
app.UseHangfireDashboard("/jobs", new DashboardOptions {
Authorization = new[] { new clsHangFireAuthFilter() }
});
//Remove Duplicte HangFire Server
var varMonitoringApi = JobStorage.Current.GetMonitoringApi();
var varServerList = varMonitoringApi.Servers().Where(r => r.Name.Contains("job.fiscal.io"));
foreach( var varServerItem in varServerList) {
JobStorage.Current.GetConnection().RemoveServer(varServerItem.Name);
}
HF 1.7.28
For me deleting Enqueued jobs like suggested did not work.
Instead, I had to use the following:
hangfireMonitor.Queues().ToList().ForEach(x => x.FirstJobs.Where(j => j.Value.InEnqueuedState).ToList().ForEach(x => BackgroundJob.Delete(x.Key)));
I have created an app with in app purchase and tested it with CurrentAppSimulator and works fine but when i create the package for app it fails
This is my code for which i am creating package
public async System.Threading.Tasks.Task InAppInit()
{
var listing = await CurrentApp.LoadListingInformationAsync();
// Delux Unlock - Durable
var unlockFeatureDelux = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "deluxe" && p.Value.ProductType == ProductType.Durable);
isDeluxPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureDelux.Value.ProductId].IsActive;
deluxProductID = unlockFeatureDelux.Value.ProductId;
// Standard Unlock - Durable
var unlockFeatureStandard = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "standard" && p.Value.ProductType == ProductType.Durable);
isStarndardPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureStandard.Value.ProductId].IsActive;
standardProductID = unlockFeatureStandard.Value.ProductId;
}
I am calling this method OnLaunched in App.xaml.cs
Based on our discussion here is what I would do:
The LoadListingInformationAsync method uses internet and if the user does not have an internet connection then it will throw an exception. So I suggest to wrap this whole stuff into a try/ctach block
As we see the ProductListings does not contain any item. I don't know how this list is populated, but as long as your app is not in the store I would not be surprised when that list is empty (Maybe someone can help out here... but i did not find anything regarding this in the docs). So for this I would just simply check if the feature you need is in the list... With this your package will pass the test you mentioned and you can upload it. If the list is also empty when the package is installed via the store, then something with the IAP setting is wrong (but that is related to the store..)
And a general comment: Obviously this code is not complete... You need some code for purchasing the IAPs and here we only get the Ids.. (But I think you only pasted the relevant part anyway.)
So all this in code:
public async System.Threading.Tasks.Task InAppInit()
{
try
{
var listing = await CurrentApp.LoadListingInformationAsync();
if (listing.ProductListings.ContainsKey("deluxe"))
{
// Delux Unlock - Durable
var unlockFeatureDelux = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "deluxe" && p.Value.ProductType == ProductType.Durable);
isDeluxPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureDelux.Value.ProductId].IsActive;
deluxProductID = unlockFeatureDelux.Value.ProductId;
}
else
{
//There is no deluxe IAP defined... so something with your IAP stuff is wrong...
}
if (listing.ProductListings.ContainsKey("standard"))
{
// Standard Unlock - Durable
var unlockFeatureStandard = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "standard" && p.Value.ProductType == ProductType.Durable);
isStarndardPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureStandard.Value.ProductId].IsActive;
standardProductID = unlockFeatureStandard.Value.ProductId;
}
else
{
//same as for Delux
}
}
catch
{
//Show this on the UI...
}
}
I am getting an win32 exception that I need help debugging. I have a SharePoint page that has a custom Web Part that when I browse to that page, I get the following message:
In w3wp.dmp the assembly instruction at ntdll!RtlReportCriticalFailure+62 in
C:\Windows\System32\ntdll.dll from Microsoft Corporation has caused an unknown
exception (0xc0000374) on thread 43
Unhandled exception at 0xHEX in w3wp.exe: 0xc0000374:
A heap has been corrupted
I don't really know where to begin debugging this issue and searching the internet has yielded very little results.
I have saved the DMP file and I've loaded it into the Debug Diagnostic Tool for analysis. I don't know what parts are most important, so if someone could tell me which sections I should post, I will post them.
Where I think the problem is:
I have narrowed down the location of where the problem might be. If I don't call these methods, I don't get the error. Is there something wrong with the way I'm accessing the TermStore?
private void GetTerms()
{
using (SPSite site = new SPSite(PhaseListUrl.Value))
{
var session = new TaxonomySession(site);
if (session.TermStores == null || session.TermStores.Count == 0) return;
OfficeDropdown.Items.Clear();
OfficeDropdown.Items.Add("");
var termStore = session
.TermStores
.FirstOrDefault(ts => ts.Groups.Any(g => g.Name == TaxonomyName.Value));
try
{
var group = termStore.Groups[TaxonomyName.Value];
foreach (var ts in group.TermSets)
{
if (!ts.IsAvailableForTagging) continue;
AddTerms(site, termStore, ts.Id, ts.Terms);
}
}
catch (NullReferenceException) { OfficeDropdown.Items.Add("ERROR: Check your Org Term Store Name"); }
catch (ArgumentOutOfRangeException) { OfficeDropdown.Items.Add("ERROR: Check your Org Term Store Name"); }
}
}
private void AddTerms(SPSite site, TermStore termStore, Guid tsId, TermCollection coll)
{
foreach (var t in coll)
{
if (t.IsAvailableForTagging)
{
var wssIds = TaxonomyField.GetWssIdsOfTerm(site, termStore.Id, tsId, t.Id, true, 1000);
if (wssIds.Length != 0)
{
var id = wssIds[0];
var validatedString = string.Format("{0};#{1}{2}{3}", id, t.Name, TaxonomyField.TaxonomyGuidLabelDelimiter, t.Id);
OfficeDropdown.Items.Add(new ListItem(t.Name, validatedString));
}
else
{
int id = -1;
var value = new TaxonomyFieldValue(SPContext.Current.Web.AvailableFields[new Guid("{a64c1f69-c0d6-421a-8c8a-9ef8f459d7a2}")]);
value.TermGuid = t.Id.ToString();
var dummy = value.ValidatedString;
if (dummy != null)
id = value.WssId;
var validatedString = string.Format("{0};#{1}{2}{3}", id, t.Name, TaxonomyField.TaxonomyGuidLabelDelimiter, t.Id);
OfficeDropdown.Items.Add(new ListItem(t.Name, validatedString));
}
}
AddTerms(site, termStore, tsId, t.Terms);
}
}
UPDATE:
The bug was in the TaxonomyField. I was accessing terms cross site collection and the IDs hadn't been generated. Also look out for TermStore IDs not being the same cross site collection (and know where you are calling from and where you are calling to!)
Here are some suggestions.
Pull up ULS Log Viewer and study the logs, if you hit the page and get that error, it should be logged there.
Check the application event logs on the web front-end server(s).
Have you also tried attaching to the W3P.exe process and debug the solution? (Assuming it's not the production environment of course).