WinRT:使用 GetFileFromApplicationUriAsync() 加载静态数据静态、加载、数据、WinRT

2023-09-06 05:51:12 作者:画舫烟中浅

我的 Windows 8 应用程序中有一些数据,这些数据应该是附带的,只是一些静态数据.事实上:这是一个简单的 xml 文件,应该反序列化.

I have some data in my windows 8 application which should be shipped with and is just some static data. In fact: It's a simple xml file which should get deserialized.

数据保存在 Assetsdata.xml 中(Assets 是空白应用模板中的默认文件夹).

The data is saved in Assetsdata.xml (Assets is the default folder from the Blank App Template).

我正在使用这段代码来访问它:

I'm using this piece of code to access it:

private static async Task<MyObject> Load()
{
    if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
    {
        return new SampleData();
    }

    var uri = new Uri("ms-appx:///Assets/data.xml");
    Debug.WriteLine("Getting file from Application");
    var file = await StorageFile.GetFileFromApplicationUriAsync(uri);
    Debug.WriteLine("Opening file for reading async");
    var stream = await file.OpenStreamForReadAsync();

    var serializer = new XmlSerializer(typeof(MyObject));

    Debug.WriteLine("Begin deserialization");
    var result = (MyObject)serializer.Deserialize(stream.AsInputStream().AsStreamForRead());

    return result;
}

调用方法:

public static MyObject GetMyObject()
{
    if (_myObject == null)
    {
        _myObject = Load().Result;
    }

    return _myObject;
}

有趣"的部分是:

如果我在 var uri = new Uri(...); 处设置断点并使用 F11 单步执行代码,一切都会按预期进行.我得到了所有的调试行,我的应用程序根据需要显示了静态数据.

If I set a breakpoint at var uri = new Uri(...); and use F11 to step through the code, everything works as expected. I get all of the debug lines and my Application shows the static data as wanted.

如果我不设置断点并且不跳过这段代码,我只会得到 Getting a file from Application 的 Debug 输出,并且不会再发生任何事情.GetFileFromApplicationUriAsync() 似乎永远不会回来.我等了五分钟多,但仍然没有任何反应.

If I don't set a breakpoint and don't step over this piece of code, I only get the Debug output of Getting a file from Application and nothing more happens. It seems that GetFileFromApplicationUriAsync() never comes back. I waited more than five minutes but still nothing happend.

有人知道吗?

推荐答案

感谢您发布代码.请尝试更改您的方法 Load 如下:

Thanks for posting code. Please try to change your method Load as the following:

//your code
var file = await StorageFile.GetFileFromApplicationUriAsync(uri).AsTask().ConfigureAwait(false);
//your code
var stream = await file.OpenStreamForReadAsync().ConfigureAwait(false);
//your code

这里的主要区别是 AsTask().ConfigureAwait(false)

很高兴听到它正在工作.解释很简单:当您在 GUI 线程上使用 task.Resulttask.Wait() 并结合 await 关键字时,您会导致僵局.发生这种情况是因为在 awaiting 代码在它被调用的同一上下文中恢复之后(在您的情况下 - GUI 线程).并且由于当前等待任务完成的 GUI 线程(通过 ResultWait())出现死锁,并且永远不会调用 await 关键字之后的代码.ConfigureAwait(false) 指定可以忽略当前上下文,从而允许您的代码成功完成.更多细节在这里:http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

Good to hear that it's working. Explanation is quite simple: when you use task.Result or task.Wait() on GUI thread in conjunction with await keyword you're causing deadlock. This happens because after awaiting code is resumed on the same context it was invoked (in your case - GUI thread). And because GUI thread currently waiting for task to complete (via Result or Wait()) deadlock arises and code after await keyword will never be invoked. ConfigureAwait(false) specifies that current context can be ignored and thus allows your code to complete successfully. More details on this here: http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html