Timetrigger not firing backgroundtask UWP - c#

I have the same problem as this guy over here: UWP Timetrigger not working
but I can't comment the question because my reputation is not high enough, so I'm creating a new question.
As I said, I have the same problem. I registered the background task, but nothing happens. My background task is located in a seperate project (Runtime Component). So that's not the problem.
This is the method I made to register the task:
public static BackgroundTaskRegistration Register(string name, string taskEntryPoint, IBackgroundTrigger trigger, IBackgroundCondition condition)
{
var foundTask = BackgroundTaskRegistration.AllTasks.FirstOrDefault(x => x.Value.Name == name);
if (foundTask.Value != null)
return (BackgroundTaskRegistration)foundTask.Value;
var builder = new BackgroundTaskBuilder();
builder.Name = name;
builder.TaskEntryPoint = taskEntryPoint;
builder.SetTrigger(trigger);
if (condition != null)
builder.AddCondition(condition);
return builder.Register();
}
and this is how I call it:
BackgroundTaskRegister.Register(nameof(NotificationTask), $"Epguides.Background.{_backgroundTaskName}", new TimeTrigger(30, true), null);
When I debug my application and use Lifecycle Events in Visual studio to test my background task, everything works fine. So the problem is not the task.
When I inspect the BackgroundTaskRegistration result I see that the property trigger is null. on the MSDN page of BackgroundTaskRegistration.Trigger it says the following
This is not intended for use in your code. For all unsupported trigger types, the value returned by this property is null.
So from what I understand is that TimeTrigger is an unsupported trigger type, because Trigger is null.
This is what is declared in the manifest file
Is there someone that can explain why it is not working. I'm using version 10.0.10586

You can confirm that the your task is registered or not by using powershell.
Open powershell with administrative rights, and run 'Get-AppBackgroundTask'. All of registered tasks are listed. If you can't find your task from the list, there are some problems at registration.
Have you add the background task project as a reference to your main app?
Have you call the BackgroundExecutionManager.RequestAccessAsync()? You should call it before registering, from UI thread.
I have a sample app of background task with timetrigger on the store. It's hidden from storefront and search, but you can download it from following link:
https://www.microsoft.com/store/p/ddlgbgtasktrial/9nblggh4s785
This app regist a simple background task with 15min interval timetrigger. This task just output the debugmessage to the logfile. The app shows a log. If it works well, you can see the debug output with about 15min intervals.
I've confirmed that the app works with Win10 desktop 10586.494 and mobile 14393.0.

I had exactly same problem with TimeTrigger (Application trigger was working without any issues) and I followed every step from MSDN regarding BackgroundTask in UWP. But ONLY below "magic line" helped me to solve - BIG THANKS to #Canol Gökel for his reply in comments (I think it deserve separate answer):
BackgroundExecutionManager.RemoveAccess(); // This is the magic line!
var backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();
Time trigger is part of UWP background task sample (Scenario 4) which was working for me. But this line is not used there at all. Instead it is used in NFC sample during check if application was updated:
private static async Task<bool> DoBackgroundRequestAccess()
{
String appVersion = String.Format("{0}.{1}.{2}.{3}",
Package.Current.Id.Version.Build,
Package.Current.Id.Version.Major,
Package.Current.Id.Version.Minor,
Package.Current.Id.Version.Revision);
if ((string)Windows.Storage.ApplicationData.Current.LocalSettings.Values["AppVersion"] != appVersion)
{
// Our app has been updated
Windows.Storage.ApplicationData.Current.LocalSettings.Values["AppVersion"] = appVersion;
// Call RemoveAccess
BackgroundExecutionManager.RemoveAccess();
}
BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
return status == BackgroundAccessStatus.AlwaysAllowed
|| status == BackgroundAccessStatus.AllowedSubjectToSystemPolicy;
}

Related

Win 10 IOT thread deadlocking in UWP

What I want to do:
- synchronously (or even asynchronously) load settings from USB drive before first page loads
What I did:
- in OnLaunched method for App.xaml.cs I invoked this static function:
public static async void LoadSettings(string folderName = "Config", string fileName = "Settings.xml")
{
try
{
StorageFile configFile = null;
// scan through all devices
foreach (var device in await KnownFolders.RemovableDevices.GetFoldersAsync().AsTask().ConfigureAwait(false))
{
// folder that should have configuration
var configFolder = await device.GetFolderAsync(folderName).AsTask().ConfigureAwait(false);
if (configFile != null && configFolder != null && await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false) != null)
{
throw new Exception("More than one configuration file detected. First found configuration file will be used.");
}
else
configFile = await configFolder.GetFileAsync(fileName).AsTask().ConfigureAwait(false);
}
if (configFile == null)
throw new Exception("Configuration file was not found, please insert device with proper configuration path.");
string settingString = await FileIO.ReadTextAsync(configFile).AsTask().ConfigureAwait(false);
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
using (TextReader reader = new StringReader(settingString))
{
AppSettings = (Settings)serializer.Deserialize(reader); // store settings in some static variable
}
}
catch (Exception e)
{
//return await Task.FromResult<string>(e.Message);
}
//return await Task.FromResult<string>(null);
}
As you can see right now it's async void method, so I don't even want to synchronize it in any way with UI thread. It should just fire and do something. With ConfigureAwait(false) I want to be sure that it will never try to return to context. These returns at the end are remnants of other things I tried (I wanted to do this better way, this is the most primitive solution and it still doesn't work).
Anyway, because that's where the fun begins: everything works well when I debug application on local machine with Win 10. And I get deadlocked thread on Win 10 IOT installed on Raspberry Pi 3 (I installed it from the scratch today, last version).
But deadlock is not the weirdest thing. Weirdest thing is when it appears.
Like I said, invocation of this method looks like that:
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Configuration.Settings.LoadSettings();
After that everything in this method goes normally, so I navigate to my first page somewhere below:
if (e.PrelaunchActivated == false)
{
if (rootFrame.Content == null)
{
rootFrame.Navigate(typeof(LogScreen), e.Arguments);
}
Window.Current.Activate();
}
Everything still works. User needs to write his code, I check if this code is available in settings and after that user can press "OK" to move to next page. Somewhere in LogScreenViewModel this method is responsible for that:
private void GoForward(bool isValid)
{
try
{
_navigationService.NavigateTo("MainPage"); // it's SimpleIoc navigation from MVVMLight
}
catch (Exception e)
{
Debug.WriteLine($"ERROR: {e.Message}");
}
}
And deadlock happens when _navigationService.NavigateTo("MainPage") is reached. Basically right now UI thread freezes. If I wait for long enough I will see catched exception in Output saying that messenger seemed occupied (I can't show the screen because I don't have access to that Raspberry right now) and after some timeout this thread was killed (like 30 seconds or something) - after that UI thread unlocks and application proceeds to MainPage. It doesn't happen on PC - MainPage appears immediately, no exceptions, no deadlocks.
I tried waiting on first page for like 1 minute to check if some deadlock exception would fire on it's own - but it doesn't. It will fire ONLY after I try to proceed to next page.
What else I tried instead of this fire-and-forget approach:
Making OnLaunched async and await LoadSettings returning Task - same thing happens in the same place, and no problem on PC.
Using:
Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, async () => await Configuration.Settings.LoadSettings(); ).AsTask().Wait(); If I remember correctly it deadlocked immediately on Wait(), even with ConfigureAwait(false) everywhere, but it also happened on PC.
Allowing LogScreen to load, make it's OnNavigatedTo method async and await LoadSettings - same deadlock in same place
Allowing LogScreen to load and use Dispatcher from there like in point 2. It deadlocked the same way after reaching Wait(), on PC too.
Trying to force LoadSettings to be fully synchronous by replacing every await with AsTask().GetAwaiter().GetResults(). It worked well on PC... and of course deadlock on Raspberry.
What am I missing? What else can I try? Because to be honest right now it looks to me that Win 10 IOT .NET runtime is bugged or something.
I think I resolved the issue. This code was generally speaking not mine and after some digging I noticed that someone before me tried to list some other external devices while navigating to MainPage. It was not really async-safe code (someone probably wasn't aware of synchronization context) and it worked on Win 10 only because on desktop it was looking for COM0 device and I only have COM2, so method causing trouble was not even invoked at all.
I still have no idea how related it was to my configuration (because it somehow was working without it), but after I fixed issues with this old not-async-safe code it started to behave as expected.

Running IBackgroundTask on Windows 10

I have a UAP application, and when I debug on a Windows 10 Phone, IBackgroundTask is triggered automatically. When I debug on Local Machine (Windows 10 x86), it isn't called at all. How can I trigger it?
A simple way is to set a system trigger. In your manifest, you need a "Background Tasks" declaration, with a "System event" property.
In your C# code, you have to register your task and you can bind the task to a particular event system like "NetworkStateChange" :
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
task.Value.Unregister(true);
}
var result = await BackgroundExecutionManager.RequestAccessAsync();
if (result == BackgroundAccessStatus.Denied)
{
return;
}
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();
builder.Name = "<task name>";
builder.TaskEntryPoint = "<task entry point>";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.NetworkStateChange, false));
var registration = builder.Register();
With this code, you can launch the task with a manual manipulation on the network (switch wifi or unplung your cable).
When debugging, you can trigger a background task directly from Visual Studio 2015. There's a drop-down menu called Lifecycle Events that lets you invoke Suspend, Resume and any registered background tasks. Set a breakpoint in your task beforehand. (In my case the class implementing the background task is called NotifyChanges.)

Windows 10 Universal App - Geofence Background task not being triggered

I'm trying to create a Windows UAP (C#) to constantly log location data in a background task, for now all I'm trying to do is start the background task off of a geofence trigger.
I've followed a lot of guides for how to do this, I've added the entry point in the Package.appxmanifest to "BackgroundTask.LocationBackgroundTask" and selected the location property.
I'm then registering the task using the following:
var result = await BackgroundExecutionManager.RequestAccessAsync();
var builder = new BackgroundTaskBuilder();
builder.Name = BackgroundTaskName;
builder.TaskEntryPoint = BackgroundTaskEntryPoint;
builder.SetTrigger(new LocationTrigger(LocationTriggerType.Geofence));
var geofenceTask = builder.Register();
I use the following code to verify if the background task is registered and it returns true to indicate that the task is registered:
public bool IsTaskRegistered()
{
var Registered = false;
var entry = BackgroundTaskRegistration.AllTasks.FirstOrDefault(keyval => keyval.Value.Name == BackgroundTaskName);
if (entry.Value != null)
Registered = true;
return Registered;
}
The problem I'm having is that the Run method in the background task is just not getting triggered.
To verify the background task itself is all good, I swapped out the trigger type for builder.SetTrigger(new SystemTrigger(SystemTriggerType.PowerStateChange, true)); (and updated the Package.appxmanifest to have the system event property). This then worked fine as the background task was triggered as I'd expect when I unplugged the power source from my laptop.
The other thing to note is that when debugging I don't see the background task under the Lifecycle Events whereas I do when testing with the SystemTrigger.
The problem does therefore seem to be specific to the geofence triggering. I'm starting to pull my hair out a bit over this so would be grateful for any suggestions.

Making file picker asynchronous - Windows Phone 8.1

I tried to make File open picker asynchronous using TaskComplectionSource however sometimes I get my application closed with -1 return value, sometimes I get exception like:
[System.Runtime.InteropServices.COMException] = {System.Runtime.InteropServices.COMException (0x80004005): Unspecified error
Unspecified error
at Windows.Storage.Pickers.FileOpenPicker.PickSingleFileAndContinue()
at PhotosGraphos.Mobile.Common.StorageFileExtensions.<PickSingleFileAsyncMobile..
Code:
public static class StorageFileExtensions
{
private static TaskCompletionSource<StorageFile> PickFileTaskCompletionSource;
private static bool isPickingFileInProgress;
public static async Task<StorageFile> PickSingleFileAsyncMobile(this FileOpenPicker openPicker)
{
if (isPickingFileInProgress)
return null;
isPickingFileInProgress = true;
PickFileTaskCompletionSource = new TaskCompletionSource<StorageFile>();
var currentView = CoreApplication.GetCurrentView();
currentView.Activated += OnActivated;
openPicker.PickSingleFileAndContinue();
StorageFile pickedFile;
try
{
pickedFile = await PickFileTaskCompletionSource.Task;
}
catch (TaskCanceledException)
{
pickedFile = null;
}
finally
{
PickFileTaskCompletionSource = null;
isPickingFileInProgress = false;
}
return pickedFile;
}
private static void OnActivated(CoreApplicationView sender, IActivatedEventArgs args)
{
var continuationArgs = args as FileOpenPickerContinuationEventArgs;
sender.Activated -= OnActivated;
if (continuationArgs != null && continuationArgs.Files.Any())
{
StorageFile pickedFile = continuationArgs.Files.First();
PickFileTaskCompletionSource.SetResult(pickedFile);
}
else
{
PickFileTaskCompletionSource.SetCanceled();
}
}
}
What's weird - this bug is hardly reproduced while debugging. Does anyone have any idea what could be reason of that?
Don't do that (don't try to turn Continuation behaviour into async). Why?
Normally when your app is put into the background (for example when you call file picker), it's being suspended, and here is one small pitfall - when you have a debugger attached, your app will work without being suspended. Surely that can cause some troubles.
Note also that when you normally run your app and you fire a picker, then in some cases your app can be terminated (low resources, user closes it ...). So you need here two things which are added by VS as a template: ContinuationManager and SuspensionManager. More you will find at MSDN. At the same link you will find a good procedure to debug your app:
Follow these steps to test the case in which your app is terminated after calling the AndContinue method. These steps ensure that the debugger reattaches to your app after completing the operation and continuing.
In Visual Studio, right-click on your project and select Properties.
In Project Designer, on the Debug tab under Start action, enable Do not launch, but debug my code when it starts.
Run your app with debugging. This deploys the app, but does not run it.
Start your app manually. The debugger attaches to the app. If you have breakpoints in your code, the debugger stops at the breakpoints. When your app calls the AndContinue method, the debugger continues to run.
If your app calls a file picker, wait until you have opened the file provider (for example, Phone, Photos, or OneDrive). If your app calls an online identity provider, wait until the authentication page opens.
On the Debug Location toolbar, in the Process dropdown list, select the process for your app. In the Lifecycle Events dropdown list, select Suspend and Shutdown to terminate your app but leave the emulator running.
After the AndContinue operation completes, the debugger reattaches to your app automatically when the app continues.
I've changed file picker to standard way provided by #Romasz - it still was crashing. I've been debugging it for hours and I get same COMException but sometimes with information provided:
"GetNavigationState doesn't support serialization of a parameter type which was passed to Frame.Navigate"
It seems that code with TaskCompletionSource works and there is nothing wrong with that. I found out in msdn documentation for Frame
Note: The serialization format used by these methods is for internal use only. Your app should not form any dependencies on it. Additionally, this format supports serialization only for basic types like string, char, numeric and GUID types.
And I was passing my model-class object in navigation parameter - so it was kept in navigation stack therefore it couldn't be serialized. The lesson is: do not use non-primitive types for navigation parameter - Frame.Navigate should disallow such navigation and throw exception - but it doesn't..
EDIT:
Another bug - if you bind tapped (let say button tapped) or event like that to command which launch FileOpenPicker you need to check if picker.PickFile.. was called before - otherwise when you tap fast on that button you'll get few calls to picker.PickFile.. and UnauthorizedAccessException will be thrown.

Registering a background task in WinRT

I'm trying to register a background task and I'm getting some strange behaviour. I appears that the task itself is registering and firing at the right time; however, when it does fire it's closing my program down (with no error).
I suspect that the reason is linked to the fact that the program is not asking me is I want to allow a background task to run when I launch. I have created a declaration for the background task as a system event, and am registering like this from the App.Xaml.cs:
var builder = new BackgroundTaskBuilder();
builder.Name = "NewTask";
builder.TaskEntryPoint = "ConnectionMonitor.CheckInternet";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.InternetAvailable, false));
BackgroundTaskRegistration task = builder.Register();
So, I believe my question is: why would it not ask me for permission to run a background task (which I assume will give me the answer to my main problem of why it is crashing)?
I'm not sure whether it matters, but this is a Windows Universal app (the app.xaml.cs above is in the Shared project.
The task looks like this:
BackgroundTaskDeferral _deferral = taskInstance.GetDeferral();
bool newConnected = IsConnected();
if (connected != newConnected)
{
connected = newConnected;
var notifier = ToastNotificationManager.CreateToastNotifier();
var template = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var element = template.GetElementsByTagName("text")[0];
element.AppendChild(template.CreateTextNode(connected ? "Connection available" : "Connection lost"));
var toast = new ToastNotification(template);
notifier.Show(toast);
}
_deferral.Complete();
You asked: why would it not ask me for permission to run a background task?
The answer is, unless your background task requires lock screen access, it does not require the user's permission to be registered. There is no user prompt, by design. One of the intents of this design is that it allows you to register a task from another task.
In Windows, you do not need to call BackgroundExecutionManager.RequestAccessAsync() except for lock screen access. Calling it will give you more quota but will require the user to approve the task.
In Windows Phone, calling RequestAccessAsync() is required no matter what, but never prompts the user with a UI. For this reason the logic in your Universal App can be shared but will likely have a #if to handle the registration differently, if relevant.

Categories