我需要从资源中的文本文件中读取数值(版本号)。 我将此版本号与已安装组件的版本号进行比较。 如果资源中的版本号高于安装的版本,我将新组件(数据库)从我的资源复制到用户可以使用它的本地目录。
我需要同步执行此操作,因为我的应用程序无法在没有数据库的情况下工作。
但是,我没有看到任何同步的方法。 MS强迫我用这样的异步任务来做这件事:
private async Task<string> ResourcesReadTextFile(string uFileName)
{
string sRet = "";
try
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(cstAssets + uFileName));
using (var inputStream = await file.OpenReadAsync())
using (var classicStream = inputStream.AsStreamForRead())
using (var streamReader = new StreamReader(classicStream))
{
while (streamReader.Peek() >= 0)
{
sRet = streamReader.ReadLine();
}
}
}
catch (Exception ex)
{
Debug.Assert(false);//check here
}
return sRet;
}
现在我遇到了在将数据库复制到本地目录之前应用程序启动的情况,因为复制也需要异步完成,根本没有任何方法可以同步。 没有StorageFile.Copy()等功能。
我所使用的是:
private async void pCopyFromResourcesToLocal(string uFileName)
{
// Cant await inside catch, but this works anyway
try
{
StorageFile storfile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(cstAssets + uFileName));
await storfile.CopyAsync(ApplicationData.Current.LocalFolder);
}
catch (Exception ex)
{
Debug.WriteLine("");
}
}
这让我发疯。
人们写道Async应该被拥抱和拥抱并欣赏,但在我的情况下它只会带来麻烦。
我没有看到任何使这个事情同步的方法,我想知道为什么MS强迫我这样做。
非常感谢任何帮助。
谢谢。
代码截图:
编辑:我在这里添加了顶级方法:
public static async Task<DB> InitAppDb()
{
IFileHelper helper = DependencyService.Get<IFileHelper>();
string path = await helper.GetFilePathAndCopyFromResourcesIfNotPresent("tablet.db");
return (_dbApp = new DB(path));
}
public async Task CopyDatabaseIfNotExists(string uFileName)
{
IsolatedStorageFile nExpectedFolder = IsolatedStorageFile.GetUserStoreForApplication();
bool bCopyNewDB = false;
Task<bool> datatask = pResourceIsNewer(uFileName);
bCopyNewDB = await datatask;
if (! bCopyNewDB)
{
try
{
await ApplicationData.Current.LocalFolder.GetFileAsync(uFileName); //nExpectedFolder.GetFileAsync(dbPath);/// ApplicationData.Current.LocalFolder.GetFileAsync("preinstalledDB.db");
// No exception means it exists
return;
}
catch (System.IO.FileNotFoundException)
{
// The file obviously doesn't exist
}
}
pCopyFromResourcesToLocal(uFileName);
}
private async Task<bool>pResourceIsNewer(string uPath)
{
string sFileNameAppDBVersion =uPath + ".txt";
if (IsolatedStorageFileExist(sFileNameAppDBVersion))
{
int iAppDBVersionInstalled = Convert.ToInt32(IsolatedStorageReadTextFile(sFileNameAppDBVersion));
Task<string> datatask = ResourcesReadTextFile(sFileNameAppDBVersion);
string s = await datatask;
int iAppDBResources = Convert.ToInt32(s);
bool b = (iAppDBResources > iAppDBVersionInstalled);
return b;
}
else
{
return true;
}
}
答案 0 :(得分:5)
您所要做的就是:
//private async void pCopyFromResourcesToLocal(string uFileName) { ... }
private async Task pCopyFromResourcesToLocal(string uFileName) { ... }
然后你可以等待它:
//pCopyFromResourcesToLocal(uFileName);
await pCopyFromResourcesToLocal(uFileName);
并且在致电return (_dbApp = new DB(path));
此async
/ await
链中的任何内容都不会发生故障。
答案 1 :(得分:2)
当您说您的应用程序无法在没有数据库的情况下工作时,请记住使用await关键字就是这样,因此在异步调用返回之后,以下代码行才会执行。您可以构建代码,使其在您等待数据库重新联机时响应。
但是,您可以使用如下构造强制您的函数同步:
StorageFile.GetFileFromApplicationUriAsync(new Uri(cstAssets + uFileName)).GetAwaiter().GetResult();
或者,更好的是,请查看JoinableTaskFactory。
答案 2 :(得分:-1)
任何异步API方法都可以通过在末尾标记.GetAwaiter().GetResult()
来实现同步,如@ pm_2所说。
如果是Task<T>
结果,您可以使用.Result
,Task
结果.Wait()
。
你可以编写一个异步函数来读取你的文件,然后在顶层等待它的结果,或者你可以编写一个同步方法并等待它对异步函数的每次调用的结果。
因此微软并没有强迫你做任何事情:它只是提供了一个更简单的API,它具有异步和同步工作流程的最低标准。