StorageFolder GetFolderFromPathAsync throws Value does not fall within the expected range error

519 views Asked by At

I am trying to open a FileSaveDialog and when the user presses save, I am creating a zip in the LocalFolder and moving it over to the user selected location. With this code, the file successfully moves to the selected location, but I get an exception like 'Value does not fall within the expected range error.' when I say var storageFolder = await StorageFolder.GetFolderFromPathAsync(localfile.Path); Please help.

Here is the full code.

public async Task<bool> WriteFilesToFolder(string baseFolderName, Dictionary<string, string> contentOfFilesWithFileNames)
        {
            try
            {
                var savePicker = new FileSavePicker();
                savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;

                // Dropdown of file types the user can save the file as
                savePicker.FileTypeChoices.Add("zip", new List<string>() { ".zip" });
                // Default file name if the user does not type one in or select a file to replace
                savePicker.SuggestedFileName = baseFolderName;

                StorageFile localfile = await savePicker.PickSaveFileAsync();
                if (localfile == null)
                {
                    return false;
                }

                string pathOfZip = string.Empty;
                StorageFolder destinationfolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(baseFolderName, CreationCollisionOption.ReplaceExisting);
                if (destinationfolder != null)
                {
                    StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", destinationfolder);

                    for (int i = 0; i < contentOfFilesWithFileNames.Count; i++)
                    {
                        var item = contentOfFilesWithFileNames.ElementAt(i);
                        string fileNameToCreate = item.Key;
                        string formattedFileName = fileNameToCreate.Replace(",", string.Empty).Replace("/", "-").Replace(":", "-");
                        var file = await destinationfolder.CreateFileAsync(string.Format("{0}.html", formattedFileName), CreationCollisionOption.ReplaceExisting);
                        var res = await WriteStorageFileAction(file, item.Value);
                    }

                    await Task.Run(() =>
                    {
                        string temp = Directory.GetParent(destinationfolder.Path).FullName;
                        pathOfZip = string.Format("{0}\\{1}{2}.zip", temp, baseFolderName, DateTime.Now.ToString("yyyy-MM-dd_hh-mm"));
                        if (File.Exists(pathOfZip))
                        {
                            File.Delete(pathOfZip);
                        }

                        // Zipping file into the same folder throws exception that its being used by an other process.
                        // So zip to new location.
                        ZipFile.CreateFromDirectory(destinationfolder.Path, pathOfZip,
                                CompressionLevel.Optimal, true);
                    });

                    if (localfile != null)
                    {
                        string faToken = StorageApplicationPermissions.FutureAccessList.Add(localfile);
                        StorageFile file = await StorageFile.GetFileFromPathAsync(pathOfZip);
                        var storageFolder = await StorageFolder.GetFolderFromPathAsync(localfile.Path); //This line throws the exception.
                        await file.MoveAsync(storageFolder);
                    }

                    await destinationfolder.DeleteAsync();
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw;
            }

            return false;
        }

Update:

Here is the Mainifest Namespaces:

<Package

xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
         xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
         xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
         xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
         xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
         IgnorableNamespaces="uap mp rescap">

I updated the Package Manifest file which looks as follows. but I have a green scribbly under rescap:Capability .

rescap:Capability

Now the error is as follows: green scribbly warning

1

There are 1 answers

13
Roy Li - MSFT On BEST ANSWER

If you want to get a StorageFolder object using StorageFolder.GetFolderFromPathAsync method, then you need to pass a folder path as parameter. The localfile object is a StorageFile object that you got from a FileSavePicker. The localfile.Path represents a location of a file, not a folder. That's why you are having this exception.

For your scenario, if you want to get the parent folder of the file that you've picked, I'd suggest you use StorageFile.GetParentAsync Method

Update:

It seems that you are picking files that are placed somewhere the UWP app doesn't have permissions to access by default. So the picker could only give you access to the single file but you can't achieve the parent folder because you don't have permission to access the folder.

Please go through File access permissions to understand this behavior better.

For such a scenario, if you want to get the parent folder that places somewhere the UWP doesn't have permission to access. using the path will be better. First, you will need to add the broadFileSystemAccess capability in the manifest file.

Like this:

     <Package
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp rescap">

<Capabilities>
    <rescap:Capability Name="broadFileSystemAccess" />
</Capabilities>

Then, after you've got the localfile object, split the path of the localfile and you could get the path of the parent folder.

Now you could call StorageFolder.GetFolderFromPathAsync like this:

StorageFolder.GetFolderFromPathAsync(parentfolderpath)