locked
StorageFile, FileSavePicker, FileOpenPicker, and Unblock

    Question

  • Windows 8.1, Visual Studio 2013: Windows Store App, Target Device is a Laptop that can also be a tablet.

    My SaveFile_Click() method uses StorageFile, FileSavePicker, and DataContractSerializer to serialize an object to a file on the hard disk. My OpenFile_Click() method reads the file and deserializes to an object. This all works except for one really annoying problem:

    Whenever I save the file, then try to open, I get the following exception:

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

    If I right-click the file and select properties, under the General tab, there's an item at the bottom titled Security: This file came from another computer and might be blocked to help protect this computer. There's also an Unblock button. If I click the Unblock button, I can read the file successfully without the exception above. If I reopen the Properties on the file, the Security:... and Unblock button are not there.

    How do I write the file WITHOUT blocking subsequent reads???????????????????

    private async void OpenFile_Click(object sender, RoutedEventArgs e)
    {
        bool unsnapped = await this.EnsureUnsnapped();
        if (unsnapped)
        {
            try
            { 
                FileOpenPicker openPicker = new FileOpenPicker();
                openPicker.ViewMode = PickerViewMode.List;
                openPicker.FileTypeFilter.Add(".txt");
                openPicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
    
                StorageFile _storageFile = await openPicker.PickSingleFileAsync();
    
                if (_storageFile != null)
                {
                    // Application now has read/write access to the picked file
                    OutputTextBlock.Text = "Picked file: " + _storageFile.Name;
    
                    List<Type> listOfTypes = new List<Type>
                        {
                            typeof(MyBase)
                        };
    
                    DataContractSerializerSettings dataContractSerializerSettings = new DataContractSerializerSettings();
                    dataContractSerializerSettings.MaxItemsInObjectGraph = int.MaxValue;
                    dataContractSerializerSettings.PreserveObjectReferences = true;
                    //dataContractSerializerSettings.RootNamespace = new XmlDictionaryString(new XmlDictionary(), "http://Microsoft.ServiceModel.Samples", 0);
                    dataContractSerializerSettings.KnownTypes = listOfTypes;
    
                    DataContractSerializer serializer =
                        new DataContractSerializer(typeof(MyChild), dataContractSerializerSettings);
    
                    Stream stream = await _storageFile.OpenStreamForReadAsync();
                    MyChild myChild = (MyChild)serializer.ReadObject(stream);
                }
            }
            catch(Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }
        else
        {
            OutputTextBlock.Text = "Operation cancelled.";
        }   
    }
    
    //private string filename = "MyFile.txt";
    
    private async void SaveFile_Click(object sender, RoutedEventArgs e)
    {
        bool unsnapped = await this.EnsureUnsnapped();
        if (unsnapped)
        {
            MyChild myChild = new MyChild();
    
            FileSavePicker savePicker = new FileSavePicker();
            savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
            savePicker.FileTypeChoices.Add("MyFile", new List<string>() { ".txt" });
            savePicker.SuggestedFileName = "MyFile";
    
            StorageFile storageFile = await savePicker.PickSaveFileAsync();
            IRandomAccessStream sessionRandomAccess = await storageFile.OpenAsync(FileAccessMode.ReadWrite);
            IOutputStream sessionOutputStream = sessionRandomAccess.GetOutputStreamAt(0);
    
            List<Type> listOfTypes = new List<Type>
            {
                typeof(MyBase)
            };
    
            DataContractSerializerSettings dataContractSerializerSettings = new DataContractSerializerSettings();
            dataContractSerializerSettings.MaxItemsInObjectGraph = int.MaxValue;
            dataContractSerializerSettings.PreserveObjectReferences = true;
            //dataContractSerializerSettings.RootNamespace = new XmlDictionaryString(new XmlDictionary(), "http://Microsoft.ServiceModel.Samples", 0);
            dataContractSerializerSettings.KnownTypes = listOfTypes;
    
    
            var sessionSerializer = new DataContractSerializer(typeof(MyChild), dataContractSerializerSettings);
            sessionSerializer.WriteObject(sessionOutputStream.AsStreamForWrite(), myChild);
            await sessionOutputStream.FlushAsync();
    
    
            // Let Windows know that we're finished changing the file so the 
            // other app can update the remote version of the file.
            // Completing updates may require Windows to ask for user input.
            FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(storageFile);
            if (status == FileUpdateStatus.Complete)
            {
                OutputTextBlock.Text = "File " + storageFile.Name + " was saved."; ;
            }
            else
            {
                OutputTextBlock.Text = "File " + storageFile.Name + " couldn't be saved.";
            }
        }
        else
        {
            OutputTextBlock.Text = "Operation cancelled.";
        }
    
    }
    
    internal async Task<bool> EnsureUnsnapped()
    {
        // FilePicker APIs will not work if the application is in a snapped state.
        // If an app wants to show a FilePicker while snapped, it must attempt to unsnap first
        bool unsnapped = ((ApplicationView.Value != ApplicationViewState.Snapped) || ApplicationView.TryUnsnap());
        if (!unsnapped)
        {
            MessageDialog messageDialog = new MessageDialog("Cannot unsnap the sample.", "Warning");
            await messageDialog.ShowAsync();
        }
    
        return unsnapped;
    }


    Randy

    Friday, February 21, 2014 7:41 PM

Answers

  • If you save the file, close the app (make sure it's not running at all), and reopen the app can you then open the file? If so then disposing the streams should fix the problem. You should Dispose on your streams when you are done with them so they close the underlying file.

    The Mark of the Web (the flag which marks the file as untrusted) shouldn't affect opening a file to save into it, but having an open handle to the file will.

    --Rob

    Saturday, February 22, 2014 8:17 AM
    Owner