【问题标题】:Access is Denied when Saving a Object in in local storage Windows 8 Metro App在本地存储中保存对象时拒绝访问 Windows 8 Metro App
【发布时间】:2012-08-29 11:54:18
【问题描述】:

我正在尝试将一个列表(其中 Show 是我的实现 IXmlSerializable 的类)存储到本地隔离存储。我正在使用此页面中的代码: http://metrostoragehelper.codeplex.com/ 我已经实施了问题部分中建议的更改。 当从项目列表中单击它时,我正在使用以下代码添加一个 Show 对象。

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

    }

第一个节目添加得非常好,它显示在 currentShowsRB 列表中。单击第二个项目并调用上述方法时,最后一次 LoadAsync 调用发生异常:访问被拒绝。 (来自 HRESULT 的异常:0x80070005 (E_ACCESSDENIED)) 如何解决此问题以访问本地数据存储以进行多次调用?

下面也是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;
        }
    }

我添加了 writeStream.Dispose() 行,但即使包含此行,我也会收到相同的访问被拒绝的错误消息。如果我还包括 outStream.Dispose() 行,那么我会在下面的 catch 语句中捕获一个 ObjectDisposedException。还有什么我应该做的吗?

【问题讨论】:

    标签: c# windows-8 microsoft-metro windows-runtime


    【解决方案1】:

    您没有等待 SaveAsync 完成,而是在 Save 仍在进行时尝试加载。将其更改为:

    //isoStorage.SaveASync(currentShows, "myShowsEx");
    await isoStorage.SaveASync(currentShows, "myShowsEx");   
    
    List<Show> currentShowsRB = await isoStorage.LoadASync("myShowsEx"); 
    

    编辑,awaitvoid 是一个标准问题。
    快速解决方法是:

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

    但您也可以将TaskEx.Run() 移动到SaveASync() 中。并且给定一个以 Async 结尾的名称,它不应该是 void,而是:

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

    我不相信 Serialize 有异步版本,所以它保持在 TaskEx.Run()

    【讨论】:

    • 谢谢!您不能等待 void 方法,因此我必须创建一个虚拟返回类型。有没有比 return default(T) 更优雅的解决方案?
    【解决方案2】:

    这个块可以缩短为:

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

    因为您可以直接从 XmlSerializer 类中的流中读取/写入。

    您可能还会发现 CreationCollisionOption.ReplaceExisting 可能会导致问题,并且 OpenIfExists 会导致文件被序列化程序根据需要覆盖。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-17
      • 2017-09-29
      • 2013-09-10
      • 1970-01-01
      • 2020-02-18
      • 2017-02-03
      • 1970-01-01
      相关资源
      最近更新 更多