Search code examples
c#uwpxbox-one

Xbox One CopyAsync failing in Retail Mode only


Basically the following code copies an entire folder from the app installation into the LocalCacheFolder so they can be manipulated/updated. In this case the contents of the folder called 'Data'

This code works fine on mobile, desktop and on Xbox in Dev Mode, but this line fails on Xbox in Retail Mode:

await file.CopyAsync(destinationFolder, file.Name, NameCollisionOption.FailIfExists);

This is also on a fresh install so I know the file(s) don't already exist.

Is there a different way to achieve this in Retail Mode, although in theory all UWP code should work across devices.

private async Task setupdatabase()
{
    StorageFolder destinationContainer = Windows.Storage.ApplicationData.Current.LocalCacheFolder;
    string root = Windows.ApplicationModel.Package.Current.InstalledLocation.Path;
    string path = root + @"\Data";

    StorageFolder sfolder = await StorageFolder.GetFolderFromPathAsync(path);

    await CopyFolderAsync(sfolder, destinationContainer);
}

public static async Task CopyFolderAsync(StorageFolder source, StorageFolder destinationContainer, string desiredName = null)
{
    StorageFolder destinationFolder = null;
    destinationFolder = await destinationContainer.CreateFolderAsync(desiredName ?? source.Name, CreationCollisionOption.OpenIfExists);

    foreach (var file in await source.GetFilesAsync())
    {
         await file.CopyAsync(destinationFolder, file.Name, NameCollisionOption.FailIfExists);
    }

    foreach (var folder in await source.GetFoldersAsync())
    {
         await CopyFolderAsync(folder, destinationFolder);
    }
}

Solution

  • Seems like a bug with CopyAsync on the Xbox in Retail Mode

    Replacing:

    await file.CopyAsync(destinationFolder, file.Name, NameCollisionOption.FailIfExists);
    

    with:

    StorageFile sourcefile = null;
    string sourcefiletext = null;
                try
                {
                    sourcefile = await source.GetFileAsync(file.Name);
                    sourcefiletext = await FileIO.ReadTextAsync(sourcefile);
                }
                catch (Exception e)
                {
                    Debug.WriteLine "Read source error:" + e.ToString();
                }
    
                try
                {
    
                    StorageFile destfile = await destinationFolder.CreateFileAsync(file.Name, CreationCollisionOption.FailIfExists);
                    await Windows.Storage.FileIO.WriteTextAsync(destfile, sourcefiletext);
                }
                catch (Exception e)
                {
                    Debug.WriteLine "Write dest error:" + e.ToString();
                }
    

    Basically breaking it into 2 separate operations fixed the problem and my app now runs normally. This is now being submitted as a bug report

    Update: not quite a bug, but a feature, from Microsoft:

    The issue here is that the package install folder is encrypted on Xbox retail mode.  A package has permission to read it's own files which is why the ReadTextAsync+WriteTextAsync works. CopyAsync on the other hand attempts to copy the file with all attributes associated with the file (including encryption).