简体   繁体   中英

Access is Denied when Saving a Object in in local storage Windows 8 Metro App

I'm attempting to store a List (where Show is my class that implements IXmlSerializable) to the local isolated storage. I'm using the code from this page: http://metrostoragehelper.codeplex.com/ I've implemented the change suggested in the Issues section. I am using the following code to add a Show object when it is clicked from an item list.

private async void addShowButton_Click_1(object sender, RoutedEventArgs e)
    {
        var isoStorage = new StorageHelper<List<Show>>(StorageType.Local);

        List<Show> currentShows = await isoStorage.LoadASync("myShowsEx");
        if(currentShows == null) {
            currentShows = new List<Show>();
        }

        currentShows.Add(currentShow);

        isoStorage.SaveASync(currentShows, "myShowsEx");


        //Read it back, for debugging to check if it has been added properly. 
        List<Show> currentShowsRB = await isoStorage.LoadASync("myShowsEx"); //Exception here

    }

The first show is added perfectly fine and it shows up in the currentShowsRB List. When a second item is clicked and the method above invoked an exception occurs on the last LoadAsync call: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) How can I get around this to access the local data store for multiple calls?

Below is also the relevant code from the StorageHelper:

public async void SaveASync(T Obj, string FileName)
    {

        FileName = FileName + ".xml";
        try
        {
            if (Obj != null)
            {
                StorageFile file = null;
                StorageFolder folder = GetFolder(storageType);
                file = await folder.CreateFileAsync(FileName, CreationCollisionOption.ReplaceExisting);

                using (var writeStream = await file.OpenAsync(FileAccessMode.ReadWrite))
                {
                    Stream outStream = Task.Run(() => writeStream.AsStreamForWrite()).Result;
                    serializer.Serialize(outStream, Obj);
                    //writeStream.Dispose(); //Added and we get UnauthorizedAccessException
                    // outStream.Dispose(); //Added ObjectDisposedException caught in catch statement below
                }
            }
        }
        catch (Exception)
        {
            throw;
        }
    }
    public async Task<T> LoadASync(string FileName)
    {
        FileName = FileName + ".xml";
        try
        {
            StorageFile file = null;
            StorageFolder folder = GetFolder(storageType);
            file = await folder.GetFileAsync(FileName);
            using (var readStream = await file.OpenAsync(FileAccessMode.Read))
            {
                Stream inStream = Task.Run(() => readStream.AsStreamForRead()).Result;
                inStream.Position = 0;
                return (T)serializer.Deserialize(inStream);
            }
        }
        catch (FileNotFoundException)
        {
            //file not existing is perfectly valid so simply return the default 
            return default(T);
            //throw;
        }
        catch (Exception)
        {
            //Unable to load contents of file
            throw;
        }
    }

The writeStream.Dispose() line I added in, but even when this is included I get the same error message of Access is Denied. If I also include the outStream.Dispose() line then I get a ObjectDisposedException being caught in the catch statement right below. Is there something else I should be doing?

You are not waiting for the SaveAsync to finish, trying to Load when the Save is still in progress. Change it to:

//isoStorage.SaveASync(currentShows, "myShowsEx");
await isoStorage.SaveASync(currentShows, "myShowsEx");   

List<Show> currentShowsRB = await isoStorage.LoadASync("myShowsEx"); 

Edit, await ing on void is a standard problem.
The quick fix is :

 await TaskEx.Run(() => isoStorage.SaveASync(currentShows, "myShowsEx"));

But you can also move the TaskEx.Run() inside SaveASync() . And given a name that ends with Async, it should not be void but:

Task SaveASyncT Obj, string FileName)
{ 
    return TaskEx.Run() => { .... }
}

I don't believe there is an async version of Serialize, so it stays at TaskEx.Run() .

This block can be shortened to:

        using (var readStream = await file.OpenAsync(FileAccessMode.Read)) 
        { 
            return (T)serializer.Deserialize(readStream); 
        } 

as you can directly read/write from the stream in the XmlSerializer class.

You may also find that CreationCollisionOption.ReplaceExisting can cause issues and OpenIfExists will cause the file to be overwritten by the serializer as required.

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