UWP:部署使用 SQLite 和 Dapper 的项目
UWP: Deployment of a project that uses SQLite and Dapper
为了能够在我的 UWP 项目中使用 SQLite,我添加了 Nuget 包 System.Data.SQLite.Core 1.0.111 和 Dapper 1.60.6。它可以完美地构建和运行。但是,当我尝试将这个项目部署到 Store 时,出现了这些错误:
Windows 安全功能测试
File C:\myApp\sni.dll has failed the AppContainerCheck check.
File C:\myApp\SQLite.Interop.dll has failed the AppContainerCheck check.
支持API测试
API CryptDuplicateKey in advapi32.dll is not supported for this
application type. SQLite.Interop.dll calls this API.
API AreFileApisANSI in kernel32.dll is not supported for this
application type. SQLite.Interop.dll calls this API.
...
我检查了“使用本机工具链编译”选项,并按照 Windows App Certification Kit 和另一个 Whosebug 答案中的建议在发布配置上构建它,但问题仍然存在。
同样在 Windows App Certification Kit 测试结果中,它说
"Apply the required linker options - SAFESEH, DYNAMICBASE, NXCOMPAT,
and APPCONTAINER - when you link the app."
我使用的是 VS 2019,鉴于该项目是用 C#(而非 C++)编写的,我不确定链接器选项是否适用于我的情况。
还有一个奇怪的是,不像x86和x64包,部署arm包没有问题
这个问题可以解决吗,还是我应该完全停止使用这些 nuget 包。
暂时好像不行。所以让我写下其他可能的解决方案和我的经验。
1 - 使用 Microsoft.Data.SQLite
包
正如Xavier Xie在评论区所建议的,可以使用this guide in MSDN。它是一种在 UWP 应用程序中使用 SQLite 的普通库。
我不喜欢这个有几个原因。在我看来,它的语法有些冗长,而且上手并不容易。您需要注意安装的软件包版本。更重要的是,就我而言,您需要更改 class 的读取和更新功能,因为 class 的字段发生变化。因此,与使用像 Dapper 这样的高级库相比,它更难维护。
2 - 使用 Entity Framework
Using entity framework维护起来比较简单,但是我觉得上手比较难。我已经有一个数据库,在这种情况下,文档没有那么有用。
3 - 使用与 SQLite 不同的方法进行数据存储
因为我有一些初始数据并且它不应该变得这么大,所以我更喜欢使用 json 文件来存储和更新它们。
我用Newtonsoft Nuget Package for serialising, deserialising classes, and used ApplicationData Class来存储数据。我认为它们都非常易于使用,并且有很好的文档记录和清晰的示例。
以下是我所做的部分代码:
const string myDataFilename= "myData.json";
const string backupFolderPath = "ms-appx:///DataModel/";
async Task LoadData()
{
string json = await StorageApi.ReadFromFile(myDataFilename, backupFolderPath + myClassFilename);
try
{
myList = JsonConvert.DeserializeObject<List<myClass>>(json);
}
catch
{
// maybe do some reset logic here
await StorageApi.CopyFile(backupFolderPath + myDataFilename, myDataFilename);
await LoadData();
}
}
async public void saveData()
{
string json = JsonConvert.SerializeObject(myList);
await StorageApi.WriteToFile(myDataFilename, json);
}
我写了a wrapper class for using ApplicationData class以防链接失效,这里有一些代码:
public static async Task WriteToFile(string relativePath, string data)
{
StorageFile sampleFile = await localFolder.CreateFileAsync(relativePath,
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(sampleFile, data);
}
// Read data from a file
public static async Task<string> ReadFromFile(string relativePath, string backupPath = "")
{
try
{
StorageFile sampleFile = await localFolder.GetFileAsync(relativePath);
return await FileIO.ReadTextAsync(sampleFile);
}
catch (FileNotFoundException e)
{
Debug.WriteLine( "Relative path: {0}, backupPath: {1}, Error str: {2}", relativePath, backupPath, e.Message);
if (backupPath == "")
return "";
else
{
await CopyFile(backupPath, relativePath);
return await ReadFromFile(relativePath);
}
}
catch (IOException e)
{
Debug.WriteLine(e.Message);
}
return "";
}
public static async Task CopyFile(string src, string relativeDst)
{
try
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(
new Uri(src));
await file.CopyAsync(localFolder, relativeDst, NameCollisionOption.ReplaceExisting);
}
catch (FileNotFoundException e)
{
Debug.WriteLine(e.Message);
}
catch (IOException e)
{
Debug.WriteLine(e.Message);
}
}
注意:我暂时选择接受这个答案。如果出现解决确切问题的更好答案,我会接受。
为了能够在我的 UWP 项目中使用 SQLite,我添加了 Nuget 包 System.Data.SQLite.Core 1.0.111 和 Dapper 1.60.6。它可以完美地构建和运行。但是,当我尝试将这个项目部署到 Store 时,出现了这些错误:
Windows 安全功能测试
File C:\myApp\sni.dll has failed the AppContainerCheck check.
File C:\myApp\SQLite.Interop.dll has failed the AppContainerCheck check.
支持API测试
API CryptDuplicateKey in advapi32.dll is not supported for this application type. SQLite.Interop.dll calls this API.
API AreFileApisANSI in kernel32.dll is not supported for this application type. SQLite.Interop.dll calls this API.
...
我检查了“使用本机工具链编译”选项,并按照 Windows App Certification Kit 和另一个 Whosebug 答案中的建议在发布配置上构建它,但问题仍然存在。
同样在 Windows App Certification Kit 测试结果中,它说
"Apply the required linker options - SAFESEH, DYNAMICBASE, NXCOMPAT, and APPCONTAINER - when you link the app."
我使用的是 VS 2019,鉴于该项目是用 C#(而非 C++)编写的,我不确定链接器选项是否适用于我的情况。
还有一个奇怪的是,不像x86和x64包,部署arm包没有问题
这个问题可以解决吗,还是我应该完全停止使用这些 nuget 包。
暂时好像不行。所以让我写下其他可能的解决方案和我的经验。
1 - 使用 Microsoft.Data.SQLite
包
正如Xavier Xie在评论区所建议的,可以使用this guide in MSDN。它是一种在 UWP 应用程序中使用 SQLite 的普通库。
我不喜欢这个有几个原因。在我看来,它的语法有些冗长,而且上手并不容易。您需要注意安装的软件包版本。更重要的是,就我而言,您需要更改 class 的读取和更新功能,因为 class 的字段发生变化。因此,与使用像 Dapper 这样的高级库相比,它更难维护。
2 - 使用 Entity Framework
Using entity framework维护起来比较简单,但是我觉得上手比较难。我已经有一个数据库,在这种情况下,文档没有那么有用。
3 - 使用与 SQLite 不同的方法进行数据存储
因为我有一些初始数据并且它不应该变得这么大,所以我更喜欢使用 json 文件来存储和更新它们。
我用Newtonsoft Nuget Package for serialising, deserialising classes, and used ApplicationData Class来存储数据。我认为它们都非常易于使用,并且有很好的文档记录和清晰的示例。
以下是我所做的部分代码:
const string myDataFilename= "myData.json";
const string backupFolderPath = "ms-appx:///DataModel/";
async Task LoadData()
{
string json = await StorageApi.ReadFromFile(myDataFilename, backupFolderPath + myClassFilename);
try
{
myList = JsonConvert.DeserializeObject<List<myClass>>(json);
}
catch
{
// maybe do some reset logic here
await StorageApi.CopyFile(backupFolderPath + myDataFilename, myDataFilename);
await LoadData();
}
}
async public void saveData()
{
string json = JsonConvert.SerializeObject(myList);
await StorageApi.WriteToFile(myDataFilename, json);
}
我写了a wrapper class for using ApplicationData class以防链接失效,这里有一些代码:
public static async Task WriteToFile(string relativePath, string data)
{
StorageFile sampleFile = await localFolder.CreateFileAsync(relativePath,
CreationCollisionOption.ReplaceExisting);
await FileIO.WriteTextAsync(sampleFile, data);
}
// Read data from a file
public static async Task<string> ReadFromFile(string relativePath, string backupPath = "")
{
try
{
StorageFile sampleFile = await localFolder.GetFileAsync(relativePath);
return await FileIO.ReadTextAsync(sampleFile);
}
catch (FileNotFoundException e)
{
Debug.WriteLine( "Relative path: {0}, backupPath: {1}, Error str: {2}", relativePath, backupPath, e.Message);
if (backupPath == "")
return "";
else
{
await CopyFile(backupPath, relativePath);
return await ReadFromFile(relativePath);
}
}
catch (IOException e)
{
Debug.WriteLine(e.Message);
}
return "";
}
public static async Task CopyFile(string src, string relativeDst)
{
try
{
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(
new Uri(src));
await file.CopyAsync(localFolder, relativeDst, NameCollisionOption.ReplaceExisting);
}
catch (FileNotFoundException e)
{
Debug.WriteLine(e.Message);
}
catch (IOException e)
{
Debug.WriteLine(e.Message);
}
}
注意:我暂时选择接受这个答案。如果出现解决确切问题的更好答案,我会接受。