【问题标题】:Package.Current.InstalledLocation.GetFileAsync and StorageFile.CopyAsync not working as expectedPackage.Current.InstalledLocation.GetFileAsync 和 StorageFile.CopyAsync 未按预期工作
【发布时间】:2018-02-13 00:14:32
【问题描述】:

我需要使用 SQlite 数据库“播种”我的应用程序。我使用了@Kasper 在帖子How to deploy a database file with a Xamarin.form app? 中建议的代码。

我的 UWP 代码如下所示。

public async Task<String> GetDBPathAndCreateIfNotExists()
    {
        String filename = "birdsnbflys.db3";
        bool isExisting = false;
        try
        {
            StorageFile storage = await ApplicationData.Current.LocalFolder.GetFileAsync(filename);
            isExisting = true;
        }
        catch (Exception)
        {
            isExisting = false;
        }
        if (!isExisting)
        {
            StorageFile databaseFile = await Package.Current.InstalledLocation.GetFileAsync(filename);
            await databaseFile.CopyAsync(ApplicationData.Current.LocalFolder, filename, NameCollisionOption.ReplaceExisting);

        }
        return Path.Combine(ApplicationData.Current.LocalFolder.Path, filename);
    }

当我在“本地机器”上运行它时,它“挂起/永不返回”

StorageFile databaseFile = await Package.Current.InstalledLocation.GetFileAsync(filename);

如果我查看 Package.Current.InstalledLocation 文件夹,数据库文件就在那里。

当我在其中一个设备模拟器上运行它时,它“挂起/永不返回”

await databaseFile.CopyAsync(ApplicationData.Current.LocalFolder, filename, NameCollisionOption.ReplaceExisting);

在这种情况下,如果我退出应用程序然后重新启动它,文件现在位于 ApplicationData.Current.LocalFolder 中,因此应用程序运行。

鉴于我的应用程序的需要,我很乐意使用同步方式来执行此操作,但看起来微软除了异步之外没有提供任何东西。

关于如何按预期工作的任何想法或建议?

谢谢, 戴夫

【问题讨论】:

  • Async 是您在 UWP 应用中执行此操作的方式。不要期望发布同步 API。

标签: c# sqlite uwp xamarin.forms


【解决方案1】:

首先,我建议您使用TryGetItemAsync,而不是使用GetFileAsync。这样,您就可以避免 try-catch 块。
此外,您应该在您的情况下使用ConfigureAwait(false)。您不需要该方法在同一个线程上返回。最终,您的问题是由死锁引起的。

// The caller of this method may use ConfigureAwait(false) as well,
// depending on the call-site and result-usage.
public async Task<String> GetDBPathAndCreateIfNotExists()
{
    String filename = "birdsnbflys.db3";

    // Check if file exists
    var file = await ApplicationData.Current.LocalFolder.TryGetItemAsync(filename).ConfigureAwait(false);
    var fileExists = file != null;

    // If the file doesn't exist, copy it without blocking the task
    if (!fileExists)
    {
        var databaseFile = await Package.Current.InstalledLocation
            .GetFileAsync(filename)
            .ConfigureAwait(false);
        await databaseFile.CopyAsync(ApplicationData.Current.LocalFolder,
                                     filename,
                                     NameCollisionOption.ReplaceExisting)
                          .ConfigureAwait(false);
    }

    return Path.Combine(ApplicationData.Current.LocalFolder.Path, filename);
}

【讨论】:

  • 我将您的代码复制到我的方法中。结果是到处使用 .ConfigureAwait 我得到以下错误。错误 CS1061 'IAsyncOperation' 不包含'ConfigureAwait' 的定义,并且找不到接受'IAsyncOperation' 类型的第一个参数的扩展方法'ConfigureAwait'(您是否缺少 using 指令或程序集引用?)
【解决方案2】:

在阅读了很多关于 async/await 并查看了各种问题和答案之后,看来我的问题是由错误地调用 GetDBPathAndCreateIfNotExists 方法引起的。这是在 App 类的属性中完成的。

我的初始代码是这样的:

Task<string> bnbreproTask = DependencyService.Get<IFileHelper>().GetDBPathAndCreateIfNotExists();

我发现替换它以消除问题的是:

var dbName = Task.Run(async () => { return await DependencyService.Get<IFileHelper>()
                    .GetDBPathAndCreateIfNotExists(); })
                    .Result;

我有足够的 async/await 经验,每次尝试使用它时都会遇到麻烦,所以我不知道这是否是最好的解决方案。在这种情况下它确实有效。

戴夫

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-22
    • 2021-06-04
    • 2022-01-24
    • 2015-05-11
    相关资源
    最近更新 更多