Program Terminates when Background Event Fire - c#

I have made a Background Taks demo. It is a 95% % copy of the SOLUTION in this Question:
Windows Phone 8.1 Background Task - Can't Debug and won't fire
The complete example OF THE SOLUTION can be download here : http://1drv.ms/1qCPLMY
The problem is when my event fires the program terminates. "my" solution can be downloaded here: http://1drv.ms/1x3z7Mp
So here is "my" code :
First the class implementing IBackgroundTask
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace Tasks
{
public sealed class Upload : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
Debug.WriteLine("Hello IBackgroundTask");
//return;
var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var textElements = toastXml.GetElementsByTagName("text");
var networkStateChangeEventDetails = (taskInstance.TriggerDetails as Windows.Networking.Connectivity.NetworkStateChangeEventDetails);
if (networkStateChangeEventDetails == null)
return;
textElements[0].AppendChild(toastXml.CreateTextNode("I'm message from your task!"));
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
}
}
}
And here is the code for registering the Background taks:
private async void Button_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Registering task");
var taskRegistered = false;
var exampleTaskName = "UploadTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == exampleTaskName)
{
//taskRegistered = true;
task.Value.Unregister(true);
// break;
}
}
await BackgroundExecutionManager.RequestAccessAsync();
if (!taskRegistered)
{
Debug.WriteLine("Registering task inside");
var builder = new BackgroundTaskBuilder();
builder.Name = exampleTaskName;
builder.TaskEntryPoint = "Tasks.Upload";
builder.SetTrigger(new SystemTrigger(SystemTriggerType.NetworkStateChange, false));
BackgroundTaskRegistration task = builder.Register();
//task.Completed += new BackgroundTaskCompletedEventHandler(NetworkStateChangeTaskOnCompleted);
//task.Trigger += new BackgroundTaskCompletedEventHandler(NetworkStateChangeTaskOnCompleted);
await new MessageDialog("Task registered!").ShowAsync();
}
}
private void NetworkStateChangeTaskOnCompleted(BackgroundTaskRegistration sender, BackgroundTaskCompletedEventArgs args)
{
var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
var textElements = toastXml.GetElementsByTagName("text");
textElements[0].AppendChild(toastXml.CreateTextNode("NetworkStateChangeTaskOnCompleted() =>"));
textElements[0].AppendChild(toastXml.CreateTextNode("I'm message from your task!"));
ToastNotificationManager.CreateToastNotifier().Show(new ToastNotification(toastXml));
}
I get no exception, and no error mesage. The program just terminates, when the event fires. Same on both Device and Emulator.

I've checked your project there are couple of things you need to improve:
first and most important - your BackgroundTask must be a Windows Runtime Componenet not a Class library (as it is now) - open properties of the Background Task and change it. BackgroundTask must be a runtime component - that's why your program terminates.
you will also need to change the namespace to the project's (file's) name - in this case you will have Task.Upload (instead of Tasks.Upload). Remember also to change entry in Declarations in package.appxmanifest file.
As I've tried after this changes your app should work fine.

Related

My code is causing high CPU usage in WMI Provider host (WmiPrvSE.exe)

I've build a project in C# which at some point has to listen to a other file opening and closing. The code i use actually works but somehow every time i run my project "WMI Provider Host" will go crazy with CPU usage. First run it will hit 50% usage and each time i restart my project it will go up by like 10% until it hits 100%. I am not sure if i did something wrong in my code.
I tried putting that function into a new, clean file only to find out the same results.
This is what it looks like:
using System;
using System.Threading;
using System.Management;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string startEventName = "InstanceCreationEvent";
string stopEventName = "InstanceDeletionEvent";
string processName = "notepad.exe";
ListenForProcess(processName, startEventName, (sender, e) =>
{
Console.WriteLine("Process Started");
});
ListenForProcess(processName, stopEventName, (sender, e) =>
{
Console.WriteLine("Process Stopped");
});
}
static void ListenForProcess(string processName,
string eventName, EventArrivedEventHandler eventHandler)
{
string queryString =
$#"SELECT TargetInstance
FROM __{eventName}
WITHIN 0.1
WHERE TargetInstance ISA 'Win32_Process'
AND TargetInstance.Name='{processName}'";
using (var watcher = new ManagementEventWatcher(queryString))
{
watcher.EventArrived += eventHandler;
watcher.Start();
new Thread(() =>
{
while (true)
{
watcher.WaitForNextEvent();
}
}).Start();
}
}
}
}
I'm not sure why this is bugging WMI with it's CPU usage.
Only reference added is "System Management".
Any one here having any suggestions or know why this is happening? Thanks!
You should not mix Start() with WaitForNextEvent(). Probalby Start() will also start a background thread that waits for the same event, so mixing both approaches can cause weird side-effects.
So either:
Use EventArrived with Start() (async usage):
var watcher = new ManagementEventWatcher(queryString);
watcher.EventArrived += eventHandler;
watcher.Start();
...
watcher.Stop();
Or, use WaitForNextEvent (sync usage):
var watcher = new ManagementEventWatcher(queryString);
var event = watcher.WaitForNextEvent();
...
watcher.Stop();

RawPushNotification when app not running Windows Phone 8.1

I have been trying to write Background Task that would show raw push notification as toast. I got push notifications working when app is running.
This is my background task class:
public sealed class BackgroundNotificationsTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
RawNotification notification = (RawNotification)taskInstance.TriggerDetails;
string content = notification.Content;
Debug.WriteLine("Background raw notification obtained!");
//SendNotification(content);
}
private void SendNotification(string text)
{
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
XmlNodeList elements = toastXml.GetElementsByTagName("text");
foreach (IXmlNode node in elements)
{
node.InnerText = text;
}
ToastNotification notification = new ToastNotification(toastXml);
ToastNotificationManager.CreateToastNotifier().Show(notification);
}
}
Then I Register In MainPage.xaml.cs
private void RegisterTasks()
{
BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
var taskRegistered = false;
var exampleTaskName = "NotificationsBackground";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == exampleTaskName)
{
taskRegistered = true;
break;
}
}
if(!taskRegistered)
{
var builder = new BackgroundTaskBuilder();
builder.Name = exampleTaskName;
builder.TaskEntryPoint = "BackgroundTasks.NotificationsBackground";
builder.SetTrigger(new Windows.ApplicationModel.Background.PushNotificationTrigger());
try
{
BackgroundTaskRegistration task = builder.Register();
Debug.WriteLine("Background Task registered.");
}
catch (Exception e)
{
Debug.WriteLine("Background Task register exception: " + e.ToString());
}
}
}
Now in appxmanifest I have set 'Lock screen notifications' to Badge, then in Declarations I have added Background Task with properies Push notification selected and entry point set as BackgroundNotificationsTask.cs
![screen][2]
Am I doing something wron or is there something that I am missing?
EDIT:
Right now when i obtain push notification the app closes... anyone know why?
There are a couple of things you're doing wrong.
1) Put your BackgroundTask in a separate project
BackgroundTask projects should be Windows Runtime Components. Also make sure that your background task resides under an accessible namespace. Do not forget to reference the background task project from your app project.
2) Register the correct class
When registering your background task, always use the fully qualified class name and not the file name:
BackgroundTasks.BackgroundNotificationsTask
This is the entry point you'll have to use in the package manifest file and in your code (given that the task class is in the project explained under 1) and the namespace is called BackgroundTasks).
3) Call RequestAccessAsync()
Make sure you call this before registering any tasks:
BackgroundAccessStatus status = await BackgroundExecutionManager.RequestAccessAsync();
Edit: There is a pretty good walkthrough on MSDN https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh977055.aspx

Run an async task in Windows Phone and wait it later

I want to start a Task when my Main Page is loaded, which get my position using Xamarin.Mobile in background. And the difficult point is to wait, if this task isn't finished, when the user clicked on a button.
On Xamarin iOS, I managed to do it but when I try to do exactly the same on Windows Phone 8.0 I get an AggregateException with as message : "One or more errors occurred".
There is the code i use :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using System.Diagnostics;
using System.IO;
using Microsoft.Phone.Scheduler;
using System.Threading;
using System.Threading.Tasks;
using System.ComponentModel;
using Xamarin.Geolocation;
namespace Application.WinPhone
{
public partial class Connexion : PhoneApplicationPage
{
static Task w;
// Constructor
public Connexion()
{
InitializeComponent();
w = new Task (() =>
{
Debug.WriteLine("Start");
Geolocator geolocator = null;
geolocator = new Geolocator() { DesiredAccuracy = 50};
var t = geolocator.GetPositionAsync(8000).ContinueWith(x =>
{
Debug.WriteLine(string.Format("Latitude : {0} Longitude : {1}", x.Result.Latitude, x.Result.Longitude)); //Visual Studio's debugger indicate this line with the exception
});
t.Wait();
Debug.WriteLine("Finished");
});
w.Start();
}
private void Connexion_Click(object sender, RoutedEventArgs e)
{
w.Wait();
//Here use the position find by the task to know on which page send the user
NavigationService.Navigate(new Uri("/Inscription.xaml", UriKind.RelativeOrAbsolute));
}
}
}
If there are some grammatical errors in my post Sorry i'm French. :)
Thanks in advance for help.
First of all, you shouldn't do any heavy lifting in the constructor. That's a design flaw. Second, Windows Phone expects your app to start in a limited amount of time, i.e. 10 seconds max. So, starting the app and waiting 8 seconds on the Geolocator is probably taking too much time, hence the canceled task.
What you could do is create the Geolocator in the constructor of the page and get the position in the OnNavigatedTo event.
One thing you should really do is to rearange it with asnyc/await as you really don't need creating tasks in this case, i.e. (out of my head):
public Connexion()
{
Connexion.IsEnabled = false;
var ignore = InitAsync();
}
private async Task InitAsync()
{
Debug.WriteLine("Start");
Geolocator geolocator = null;
geolocator = new Geolocator() { DesiredAccuracy = 50};
var result = await geolocator.GetPositionAsync(8000);
Debug.WriteLine(string.Format("Latitude : {0} Longitude : {1}", result.Latitude, result.Longitude)); //Visual Studio's debugger indicate this line with the exception
Connexion.IsEnabled = true;
}
Note that button should be disabled unless action succeeds. You should also add try/catch handler in there and you'll get clearer exception (perhaps Geolocator can't be created in a non UI thread?)
Besides what Geolocator class are you actually using - Forms Labs one?

WinRT C#: Cannot save UnhandledException to Storage

I'm working on WinRT. If an unhandled exception is thrown I want to write the message text to the storage.
I added an Event handler in 'App.xaml.cs', see the code.
The exception is caught but the last line, where the file is written, crashes again -> 'exception'!
Why? Any idea?
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
this.UnhandledException += App_UnhandledException;
}
async void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;
StorageFile file= await folder.CreateFileAsync("crash.log",CreationCollisionOption.OpenIfExists);
await FileIO.AppendTextAsync(file, e.Message); // <----- crash again -----
}
Thanks
Sunny
I've been wondering the same thing and stumbled across this quite early on in my search. I've figured out a way, hopefully this will prove useful to someone else too.
The problem is that await is returning control of the UI thread and the app's crashing. You need a deferral but there's no real way to get one.
My solution is to use the settings storage, instead. I'm assuming most people wanting to do this want to do something LittleWatson style, so here's some code modified from http://blogs.msdn.com/b/andypennell/archive/2010/11/01/error-reporting-on-windows-phone-7.aspx for your convenience:
namespace YourApp
{
using Windows.Storage;
using Windows.UI.Popups;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
public class LittleWatson
{
private const string settingname = "LittleWatsonDetails";
private const string email = "mailto:?to=you#example.com&subject=YourApp auto-generated problem report&body=";
private const string extra = "extra", message = "message", stacktrace = "stacktrace";
internal static void ReportException(Exception ex, string extraData)
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = extraData;
exceptionValues[message] = ex.Message;
exceptionValues[stacktrace] = ex.StackTrace;
}
internal async static Task CheckForPreviousException()
{
var container = ApplicationData.Current.LocalSettings.Containers;
try
{
var exceptionValues = container[settingname].Values;
string extraData = exceptionValues[extra] as string;
string messageData = exceptionValues[message] as string;
string stacktraceData = exceptionValues[stacktrace] as string;
var sb = new StringBuilder();
sb.AppendLine(extraData);
sb.AppendLine(messageData);
sb.AppendLine(stacktraceData);
string contents = sb.ToString();
SafeDeleteLog();
if (stacktraceData != null && stacktraceData.Length > 0)
{
var dialog = new MessageDialog("A problem occured the last time you ran this application. Would you like to report it so that we can fix the error?", "Error Report")
{
CancelCommandIndex = 1,
DefaultCommandIndex = 0
};
dialog.Commands.Add(new UICommand("Send", async delegate
{
var mailToSend = email.ToString();
mailToSend += contents;
var mailto = new Uri(mailToSend);
await Windows.System.Launcher.LaunchUriAsync(mailto);
}));
dialog.Commands.Add(new UICommand("Cancel"));
await dialog.ShowAsync();
}
}
catch (KeyNotFoundException)
{
// KeyNotFoundException will fire if we've not ever had crash data. No worries!
}
}
private static void SafeDeleteLog()
{
ApplicationData.Current.LocalSettings.CreateContainer(settingname, Windows.Storage.ApplicationDataCreateDisposition.Always);
var exceptionValues = ApplicationData.Current.LocalSettings.Containers[settingname].Values;
exceptionValues[extra] = string.Empty;
exceptionValues[message] = string.Empty;
exceptionValues[stacktrace] = string.Empty;
}
}
}
To implement it, you need to do the same as the link above says, but to ensure the data's here in case the url ever goes down:
App.xaml.cs Constructor (BEFORE the call to this.InitializeComponent()):
this.UnhandledException += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
Obviously if you already have an UnhandledException method you can throw the call to LittleWatson in there.
If you're on Windows 8.1, you can add a NavigationFailed call too. This needs to be in an actual page (typically MainPage.xaml.cs or whatever page is first opened):
xx.xaml.cs Constructor (any given page):
rootFrame.NavigationFailed += (s, e) => LittleWatson.ReportException(e.Exception, "extra message goes here");
Lastly, you need to ask the user if they want to send the e-mail when the app re-opens. In your app's default Page's constructor (default: the page App.xaml.cs initializes):
this.Loaded += async (s, e) => await LittleWatson.CheckForPreviousException();
Or add the call to your OnLoad method if you already use it.
In this situation, await could be loosely translated to "do this job on another thread, and continue what you were doing while you wait for it to finish". Given that what your app was doing was crashing, you probably don't want it to continue doing that until you're done logging the problem. I'd suggest running your file IO synchronously in this case.
This may come a bit too late for the original question but...
as #Hans Passant suggested, avoiding await (i.e., running the FileIO.AppendTextAsync() synchronously), also seconded by #Jon, I would opt for this rather than the relatively too heavy code for LittleWatson. As the app is in some error handing state anyway (this should be a rare occurrence) I wouldn't put any blocking arising from synchronous (due to removing await) as a major downside.
Leaving the synchronous option to one side, the following await implementation worked for me:
Change await FileIO.AppendTextAsync(file, e.Message); to:
Task task = LogErrorMessage(file, e.Message)
task.Wait(2000); // adjust the ms value as appropriate
...
private async Task LogErrorMessage(StorageFile file, string errorMessage)
{
await FileIO.AppendTextAsync(file, errorMessage); // this shouldn't crash in App_UnhandledException as it did before
}

Clean up AppBar after process kill

I have written an Application Desktop Toolbar (a.k.a AppBar), it works great except for the fact that if I kill the process, the AppBar code never gets a chance to cleanup by sending an ABM_REMOVE. The problem is that this basically screws the users desktop up. The AppBar is written in .NET using interop code.
Does anyone know of a way to clean this resource up, even in the case of a process kill from TaskManager?
When a process is killed from Task Manager, no events are raised within that application. It's common to use a seperate helper application that listens for the Win32_ProcessStopTrace event for your process. You can use the WqlEventQuery, which is part of System.Management for this.
Here is some example code for this from a MegaSolutions post.
using System;
using System.Collections.Generic;
using System.Text;
using System.Management;
class ProcessObserver : IDisposable
{
ManagementEventWatcher m_processStartEvent = null;
ManagementEventWatcher m_processStopEvent = null;
public ProcessObserver(string processName, EventArrivedEventHandler onStart, EventArrivedEventHandler onStop)
{
WqlEventQuery startQuery = new WqlEventQuery("Win32_ProcessStartTrace", String.Format("ProcessName='{0}'", processName));
m_processStartEvent = new ManagementEventWatcher(startQuery);
WqlEventQuery stopQuery = new WqlEventQuery("Win32_ProcessStopTrace", String.Format("ProcessName='{0}'", processName));
m_processStopEvent = new ManagementEventWatcher(stopQuery);
if (onStart != null)
m_processStartEvent.EventArrived += onStart;
if (onStop != null)
m_processStopEvent.EventArrived += onStop;
}
public void Start()
{
m_processStartEvent.Start();
m_processStopEvent.Start();
}
public void Dispose()
{
m_processStartEvent.Dispose();
m_processStopEvent.Dispose();
}
}

Categories

Resources