简体   繁体   中英

Async call in background task doesn't work

In my app I need to scan for Wi-Fi access point in the background. I am able to start the task and initialise Wi-Fi adapter, but next async call "await scanner.ScanForNetworks()" to perform scan seem to never complete the task. Could it be the result of numerous nested async calls? If so, what could be possible workaround?

ScanningTask.cs

namespace BackgroundTaskLibrary
{
    public sealed class ScanningTask : IBackgroundTask
    {
        private BackgroundTaskDeferral deferral;
        private WiFiScanner scanner = new WiFiScanner();
        private Windows.Storage.ApplicationDataContainer localSettings;
        private DispatcherTimer timer;

        public async void Run(IBackgroundTaskInstance taskInstance)
        {
            deferral = taskInstance.GetDeferral();
            taskInstance.Canceled += TaskInstance_Canceled;
            await scanner.InitializeFirstAdapter();
            ShowToastNotification("Hi", "Hello from background"); //notification is shown

            await scanner.ScanForNetworks();
            ShowToastNotification("Hi", "Hello from background1"); //this one never gets shown
            deferral.Complete();
        }

        private void TaskInstance_Canceled(IBackgroundTaskInstance sender, 
            BackgroundTaskCancellationReason reason)
        {
            deferral.Complete();
        }

        private void ShowToastNotification(string title, string stringContent)
        {
            ToastNotifier ToastNotifier = ToastNotificationManager.CreateToastNotifier();
            Windows.Data.Xml.Dom.XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
            Windows.Data.Xml.Dom.XmlNodeList toastNodeList = toastXml.GetElementsByTagName("text");
            toastNodeList.Item(0).AppendChild(toastXml.CreateTextNode(title));
            toastNodeList.Item(1).AppendChild(toastXml.CreateTextNode(stringContent));
            Windows.Data.Xml.Dom.IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
            Windows.Data.Xml.Dom.XmlElement audio = toastXml.CreateElement("audio");
            audio.SetAttribute("src", "ms-winsoundevent:Notification.SMS");

            ToastNotification toast = new ToastNotification(toastXml);
            toast.ExpirationTime = DateTime.Now.AddSeconds(10);
            ToastNotifier.Show(toast);
        }
    }
}

WiFiAdapter.cs

namespace BackgroundTaskLibrary
{
    class WiFiScanner
    {
        //WiFi adapter instance
        public WiFiAdapter WiFiAdapter { get; private set; }
        public Geolocator _geolocator = new Geolocator();
        public Geoposition Location { get; set; }

        /// <summary>
        /// Find the fisrts available WiFi adapter and initialise it
        /// </summary>
        /// <returns></returns>
        public async Task InitializeFirstAdapter()
        {
            var access = await WiFiAdapter.RequestAccessAsync();
            if (access != WiFiAccessStatus.Allowed)
            {
                throw new Exception("WiFiAccessStatus not allowed");
            }
            else
            {
                var wifiAdapterResults =
                await DeviceInformation.FindAllAsync(WiFiAdapter.GetDeviceSelector());
                if (wifiAdapterResults.Count >= 1)
                {
                    this.WiFiAdapter =
                    await WiFiAdapter.FromIdAsync(wifiAdapterResults[0].Id);
                }
                else
                {
                    var dialog = new MessageDialog("WiFi Adapter not found.");
                    await dialog.ShowAsync();

                    throw new Exception("WiFi Adapter not found.");
                }
            }
        }

        public async Task ScanForNetworks()
        {
            if (WiFiAdapter != null)
            {
                await WiFiAdapter.ScanAsync();
            }
            else
            {
                throw new Exception("No Wi-Fi adapter");
            }

            Location = await _geolocator.GetGeopositionAsync();

            List<AccessPoint> accessPoints = new List<AccessPoint>();
            foreach(var network in WiFiAdapter.NetworkReport.AvailableNetworks)
            {
                AccessPoint ap = new AccessPoint()
                {
                    SSID = network.Ssid,
                    Mac = network.Bssid,
                    SignalStrength = network.NetworkRssiInDecibelMilliwatts,
                    Open = (int)network.SecuritySettings.NetworkAuthenticationType
                };

                accessPoints.Add(ap);
            }
            await SaveData(accessPoints);

        }

        public async Task SaveData(List<AccessPoint> accessPoints)
        {
            string info = DateTime.Now + "|" + Location.Coordinate.Point.Position.Latitude
                    + "|" + Location.Coordinate.Point.Position.Longitude + "|";
            for (int i = 0; i < accessPoints.Count; i++)
            {
                info += accessPoints[i].ToString();
            }

            info += Environment.NewLine;

            // Get the logical root folder for all external storage devices.
            StorageFolder externalDevices = Windows.Storage.KnownFolders.RemovableDevices;

            // Get the first child folder, which represents the SD card.
            StorageFolder sdCard = (await externalDevices.GetFoldersAsync()).FirstOrDefault();


            StorageFile infoFile;

            if (sdCard != null)
            {
                //check if info file exists
                try
                {
                    infoFile = await sdCard.GetFileAsync("wifiScanInfo.txt");
                }
                catch
                {
                    infoFile = await sdCard.CreateFileAsync("wifiScanInfo.txt");
                }

                await FileIO.AppendTextAsync(infoFile, info);
            }
        }
    }
}

In case you need the whole project: https://www.dropbox.com/sh/1v9mbr3xhgr3283/AACDbB7skZUI7Z5fiu0HT8r4a?dl=0

EDIT:

By subsequently simplifying ScanningTask I was able to determine, the problem is in the call "await WiFiAdapter.ScanAsync();"

I finally managed to catch an exception from "await WiFiAdapter.ScanAsync();", here is the stack trace:

Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))

   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()

   at BackgroundTaskLibrary.WiFiScanner.<ScanForNetworks>d__10.MoveNext()

However the scan was completed and the results were save in the text file as expected. What permissions might I be missing? I have declared Internet, Location and Removable Storage permissions.

It think the exception comes from the use of GeoLocator without requestAccessAsync call :

Starting in Windows 10, call the RequestAccessAsync before accessing the user's location. At that time, your app must be in the foreground and RequestAccessAsync must be called from the UI thread. Until the user grants your app permission to their location, your app can't access location data.

Source : https://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.geolocation.geolocator.aspx?f=255&MSPPError=-2147217396

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM