I am using a UWP project with a background task that is triggered by the internet being available. Once triggered, a toast notification is displayed.
The problem is that the background task seems to only run once after launching the UWP application. it even works after closing the application and restarting my computer as long as I haven't triggered it before doing so, but only if it is untriggered before restarting.
What am I doing wrong? am I missing something or misusing the background task?
For clarification, I want it to send a notification every time the internet is connected. The background task should run independent of the main application.
Below is the code for the background task:
namespace AppService
{
public sealed class testNoteUpdaterTask : IBackgroundTask
{
BackgroundTaskDeferral _deferral; // Note: defined at class scope so that we can mark it complete inside the OnCancel() callback if we choose to support cancellation
public void Run(IBackgroundTaskInstance taskInstance)
{
// Get a deferral so that the service isn't terminated.
_deferral = taskInstance.GetDeferral();
// Construct the content
new ToastContentBuilder()
.AddArgument("action", "testNote")
.AddArgument("conversationId", 9813)
.AddText("Program update avaliable for testNote")
// Buttons
.AddButton(new ToastButton()
.SetContent("testNote stuff")
.AddArgument("action", "open")
.SetBackgroundActivation())
.Show();
_deferral.Complete();
}
}
}
And here is the code which I use to register the background task inside the main UWP application:
public static BackgroundTaskRegistration RegisterBackgroundTask(string taskEntryPoint, string taskName, IBackgroundTrigger trigger, IBackgroundCondition condition = null)
{
// Check for existing registrations of this background task.
foreach (var cur in BackgroundTaskRegistration.AllTasks) {
if (cur.Value.Name == taskName){
// The task is already registered.
return (BackgroundTaskRegistration)(cur.Value);
}
}
// Register the background task.
var builder = new BackgroundTaskBuilder();
builder.Name = taskName;
builder.TaskEntryPoint = taskEntryPoint;
builder.SetTrigger(trigger);
if (condition != null) {
builder.AddCondition(condition);
}
BackgroundTaskRegistration task = builder.Register();
return task;
}
public MainPage()
{
this.InitializeComponent();
RegisterBackgroundTask("AppService.testNoteUpdaterTask", "testNoteUpdaterX", new SystemTrigger(SystemTriggerType.InternetAvailable, true));
}
I checked your code. It seems that when you are registering the SystemTrigger here:
new SystemTrigger(SystemTriggerType.InternetAvailable, true)
You are setting the oneShot parameter as true, which means the system event trigger will be used only once. Please set this value to false if you want the system event trigger to be used every time the event occurs.
More information here:SystemTrigger(SystemTriggerType, Boolean) Constructor.
Please use the following code:
new SystemTrigger(SystemTriggerType.InternetAvailable, false)
You could also take a look at the official background task sample here:
BackgroundTask Sample line 166.
Related
I'm working on the "feature" the push notification trigger available in Windows phone 8.1. My goal is to make this work with a Windows phone Silverlight 8.1 project. As far as I know, it should work based on my reading.
After 2 days, I'm totally stuck. No matter what i'm trying. When I send a raw notification to my app, my app is canceled and I'm back to the windows menu.
The output :
The program '[1852] BACKGROUNDTASKHOST.EXE' has exited with code 1 (0x1).
The program '[2712] AgHost.exe' has exited with code 1 (0x1).
State :
The app receives the notification. It trigger OnPushNotificationReceived. (After this event, the app is canceled)
The Push Notification task is declared and the entry point is defined to Push.Notification.
I create a Windows Runtime Component for Windows phone 8.1 in order to run the background task.
The background task is well registered.
private async void RegisterBackgroundTask()
{
UnregisterBackgroundTask(taskName);
BackgroundAccessStatus backgroundStatus = await BackgroundExecutionManager.RequestAccessAsync();
if (backgroundStatus != BackgroundAccessStatus.Denied && backgroundStatus != BackgroundAccessStatus.Unspecified)
{
try
{
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder();
taskBuilder.Name = taskName;
PushNotificationTrigger trigger = new PushNotificationTrigger();
taskBuilder.SetTrigger(trigger);
taskBuilder.TaskEntryPoint = "Push.Notification";
BackgroundTaskRegistration task = taskBuilder.Register();
}
catch (Exception ex)
{ }
}
}
The background task :
public sealed class Notification
{
public void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("Background starting...");
Debug.WriteLine("Background completed!");
}
}
I have no clue about what I'm doing wrong.
Is there someone who make it works ? (Not in theory)
For information, I have 2 warnings that worrying me :
I have a mismatch in the process architecture in my 2 projects. My windows phone project use "Any CPU" (can"t change that). My windows runetime component project use "ARM". If I use "Any CPU" wor my WinRT, i got an errror :
/platform:anycpu32bitpreferred can only be used with /t:exe, /t:winexe and /t:appcontainerexe
There is a conflict on a dependent assembly of the 2 projects. Seems to be
Found conflicts between different versions of the same dependent assembly. In Visual Studio, double-click this warning (or select it and press Enter) to fix the conflicts; otherwise, add the following binding redirects to the "runtime" node in the application configuration file:
Thanks in advance
I did finally make it works.
There was an error in my initial code I forgot to implement IBackgroundTask :
public sealed class Notification : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("Background starting...");
Debug.WriteLine("Background completed!");
}
}
And I had to make my Task async...
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
// perform your async task and then call deferral complete
await Test();
deferral.Complete();
}
private static async Task Test()
{
//TODO with an await
}
Hope this'll help someone.
I am trying to make a background task reschedule itself at the end of it's task. but when I go to test it doesn't seem to activate. The task runs initially from the frontend successfully. When I check the lifecycle Events after it finishes I see it's name and two blank ones. When I run the blank ones it runs it, not sure what I am doing that causes them. I am tryin to test with a 16 min time trigger but it doesn't seem to ever run again. This is the code:
var SleepyBand_TaskName = "DataHandlerTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == SleepyBand_TaskName)
{
task.Value.Unregister(true);
}
}
var builder = new BackgroundTaskBuilder();
var trigger = new TimeTrigger(16, false);
builder.Name = SleepyBand_TaskName;
builder.TaskEntryPoint = "SleepyBand_BackgroundTasks.DataHandlerTask";
builder.SetTrigger(trigger);
builder.Register();
TimeTrigger only work for lock-screen apps.
On Windows, a background task will only run using a TimeTrigger if you have requested that your app be placed on the lock screen with a call to RequestAccessAsync and the user accepts the prompt
You would need to use a MaintenanceTrigger
eI would just use System.Threading.Tasks.Task to start threads. Like this you can reshedule a task:
public void Test() {
Task.Run(() => DoSomething());
}
private void DoSomething() {
//Do Something here....
//Do Something again...
Task.Run(() => DoSomething());
}
If you need delays use something like this: https://actionscheduler.codeplex.com/
I am implementing a background task for my Windows Store Application (Win 8.1 App). I have written a very simple test class, registered it, prompted for access, but when I choose to debug the task from the debug toolbar, nothing happens. I have also waited 15 minutes multiple times today and it does not output anything. Yet, it shows (from the code perspective) that the Task is registered and I am not getting any exceptions generated.
The Background Task:
public sealed class BGFunMessage : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("Background " + taskInstance.Task.Name + " Starting...");
}
}
The Register Class:
public class RegisterWorkers
{
public static async void Run()
{
var taskRegistered = false;
var taskName = "BGFunMessage";
BackgroundTaskRegistration bTask = null;
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == taskName)
{
//taskRegistered = true;
bTask = (BackgroundTaskRegistration)(task.Value);
bTask.Unregister(true);
break;
}
}
if (!taskRegistered)
{
string entryPoint = typeof(BGFunMessage).FullName;
bTask = RegisterBackgroundTask(entryPoint, taskName);
}
}
public static BackgroundTaskRegistration RegisterBackgroundTask(string taskEntryPoint, string name)
{
var builder = new BackgroundTaskBuilder();
builder.Name = name;
builder.TaskEntryPoint = taskEntryPoint;
builder.SetTrigger(new TimeTrigger(15, false));
BackgroundTaskRegistration task = null;
try
{
task = builder.Register();
}
catch (Exception ex)
{
LiveLog.WriteException(ex, LogType.WARNING);
}
return task;
}
}
How I call it from a page in my app:
RegisterWorkers.Run();
I have tried following multiple tutorials, that all mostly say the same thing. I am also using the MSDN Samples downloaded from GitHub and I don't see anything on the surface that makes their code any different from mine (apart from that their Register method returns a Task<>). I am able to debug the Sample project background tasks, but not my own. Is there something I am doing incorrectly here? Thanks.
After many hours of troubleshooting, I have found the solution to my problem. I am unsure of why this must be the case, but it works. Originally (unspecified above), I had the Background Task in the same project as my app. The ONLY difference I could find across the board was that everywhere I seen, the background tasks were in a WINDOWS RUNTIME COMPONENT project. I pulled my code out and into its own project, and referenced the .DLL and now it all works fine.
I should note however, if anyone ever needs this fix--that now I no longer have access to any of my data or SyncContext from Azure Mobile Services as it currently stands. I have no idea what I am going to have to re-architect to make it work now, but the issue above is now resolved.
I will assume, that you should always have a Shared Code library project that your main app project should reference, that way my Background Task can also reference the shared project and I can still have access to my models and other data.
I am writing Windows Phone 8.1 Application using GeoFence API. My problem is that I can't trigger change of location in Background Task, because app exits with code 1.
I have read multiple threads about this error, but no solution solved my problem.
I have checked if my BackgroundTask is a Runtime Component, and it is.
I have checked name of my class and it is correct.
I have checked if I use any await function in my BackgroundTask function and I didn't find any.
I have checked if I registered Background Task in app manifest and yes, I did (with entry point ofc)
In fact error appears even before running Run function from BackgroundTask.
namespace BackgroundTask
{
public sealed class geoFenceBackgroundTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode("MY APP"));
toastTextElements[1].AppendChild(toastXml.CreateTextNode("Test"));
//IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
//XmlElement audio = toastXml.CreateElement("audio");
ToastNotification toast = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(toast);
}
}
}
And my register function:
async private void RegisterBackgroundTask()
{
// Get permission for a background task from the user. If the user has already answered once,
// this does nothing and the user must manually update their preference via PC Settings.
BackgroundAccessStatus backgroundAccessStatus = await BackgroundExecutionManager.RequestAccessAsync();
// Regardless of the answer, register the background task. If the user later adds this application
// to the lock screen, the background task will be ready to run.
// Create a new background task builder
BackgroundTaskBuilder geofenceTaskBuilder = new BackgroundTaskBuilder();
geofenceTaskBuilder.Name = "geoFenceBackgroundTask";
geofenceTaskBuilder.TaskEntryPoint = "BackgroundTask.geoFenceBackgroundTask";
// Create a new location trigger
var trigger = new LocationTrigger(LocationTriggerType.Geofence);
// Associate the locationi trigger with the background task builder
geofenceTaskBuilder.SetTrigger(trigger);
// If it is important that there is user presence and/or
// internet connection when OnCompleted is called
// the following could be called before calling Register()
// SystemCondition condition = new SystemCondition(SystemConditionType.UserPresent | SystemConditionType.InternetAvailable);
// geofenceTaskBuilder.AddCondition(condition);
// Register the background task
var geofenceTask = geofenceTaskBuilder.Register();
geofenceTask.Completed += (sender, args) =>
{
// MY CODE HERE
};
geofenceTask = geofenceTaskBuilder.Register();
}
I have no other ideas. Any help?
just stumbled upon a similar issue (Visual Studio stopped Debugging when I started the Background Task over the "Lifecyle-Events-Dropdown", stating "BACKGROUNDTASKHOST.EXE' has exited with code 1 (0x1)" in the Console-Output-Window.
Adding the missing reference to my Tasks-Assembly (winmd) Project in the WP8 Project solved it.
The project BackgroundTask need be (windows runtime component).
Is there an event to handle when connection status change?
For example, my app is like OutLook. I would like to handle an event to know when there is Internet connection and then to send all pending e-mails.
Now I can check periodically if there is Internet connection, but it seems a poor solution to me. I would to solve it using an event.
Your best choice would be implementing a background task. This way you could send the pending e-mails even if your app is not open any more when the internet connection becomes available.
When registering a background task you can set a trigger and a condition to configure when you want your task to run:
var trigger = new SystemTrigger(SystemTriggerType.InternetAvailable, false);
var condition = new SystemCondition(SystemConditionType.InternetAvailable);
var builder = new BackgroundTaskBuilder();
builder.Name = "Send pending e-mails task";
builder.TaskEntryPoint = "Tasks.SendPendingEmailTask";
builder.SetTrigger(trigger);
builder.AddCondition(condition);
var task = builder.Register();
Your background task must implement the IBackgroundTask interface. When the task is triggered, the Run method will be called:
public sealed class SendPendingEmailTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
var deferral = taskInstance.GetDeferral();
// send your e-mails here
deferral.Complete();
}
}