Read xml file from storage with WP8.1 StorageFile

2019-08-31 04:17发布

My application should read an xml file from storage using the StorageFile API. This has to be done async since he StorageFile API provides only async methods.

The Constructor calls the method CallAsyncMethod() which calls and (should) await the LoadXmlFromStorageAsync method.

The DataAccess() constructor does not wait for the CallAsyncMethod() and completes BEFORE the XML file is loaded. The xmlData variable is therefore not initialized when i call the GetElement() method. This is because the constructor does not wait for the async method to complete.

How can I fix this?

I guess i just don't get the async/await thing.

usage of DataAccess class

var dataAccess = new DataAccess();
dataAccess.GetElement("test"); //NullReferenceException

DataAccess class

public sealed class DataAccess
{
    private const string FileName = "data.xml";
    private const string FilePath = @"ms-appx:///Data/";
    private XDocument xmlData;

    public DataAccess()
    {
        //need to wrap this call, the async keyword does not work for construtor
        CallAsyncMethod();
    }

    private async void CallAsyncMethod()
    {
        await LoadXmlFromStorageAsync();
    }

    private async Task LoadXmlFromStorageAsync()
    {
        var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(string.Concat(FilePath, FileName)));

        using (var stream = await file.OpenStreamForReadAsync())
        {
            this.xmlData = XDocument.Load(stream);
        }
    }

    public IEnumerable<XElement> GetElement(string nodeName)
    {
        //NullReferenceException because xmlData is not initializied yet
        return this.xmlData.Descendants(nodeName).ToList();
    }
}

1条回答
Rolldiameter
2楼-- · 2019-08-31 04:28

Essentially you can't do what you're doing, unless you forcefully synchronize the code. However, I would recommend an alternative approach, where you await once GetElement is called (if it haven't been called previously). Of course, this is not a thread-safe solution.

public sealed class DataAccess
{
    private const string FileName = "data.xml";
    private const string FilePath = @"ms-appx:///Data/";
    private XDocument xmlData;

    public DataAccess()
    {
    }

    private async Task<XDocument> LoadXmlFromStorageAsync()
    {
        var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(string.Concat(FilePath, FileName)));

        using (var stream = await file.OpenStreamForReadAsync())
        {
            return XDocument.Load(stream);
        }
    }

    public async Task<IEnumerable<XElement>> GetElement(string nodeName)
    {
         if (this.xmlData == null)         
             this.xmlData = await LoadXmlFromStorageAsync();

         return this.xmlData.Descendants(nodeName).ToList();
    }

}

查看更多
登录 后发表回答