问题
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:
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();
}
}
来源:https://stackoverflow.com/questions/23311287/read-xml-file-from-storage-with-wp8-1-storagefile-api