I'm building a Windows 8 app, and now I want to use SQLite for this app. I installed SQLite for Windows Runtime through the Visual Studio 2013 extension manager, and I added sqlite-net to my project through NuGet.
I'm trying to create a database in my app.xaml.cs OnLaunched, but I get this exception when I run the project:
Unable to load DLL 'sqlite3': The specified module could not be found.
(Exception from HRESULT: 0x8007007E)
This is very strange because there is no error during compiling. Anyway, I think it tries to tell me that I need to reference an additional DLL: sqlite3.dll, but that doesn't work. I have 6 different DLLs on my file system: both debug and release versions of ARM, x64 and x86. I tried adding the x86 release version to my project but that results in this exception:
A reference to 'C:\Users\Leon\Documents\Visual Studio
2013\Projects\Googalytics\packages\SQLite\x86\sqlite3.dll' could not
be added. Please make sure that the file is accessible, and that it is
a valid assembly or COM component.
It's very sad that the documentation for sqlite-net sucks, it's very outdated (examples don't even work anymore), it's very incomplete and there is no mention of manually adding a DLL either. So I have 2 questions:
How do I fix this particular issue?
Where do I find up to date documentation for sqlite-net?
Edit: the code I use to create the DB is:
private void InitializeDatabase()
{
var db = new SQLiteConnection("Googalytics");
db.CreateTable<Account>();
db.CreateTable<WebProperty>();
db.CreateTable<Profile>();
}
I call that method from here:
InitializeDatabase();
if (rootFrame.Content == null)
{
// When the navigation stack isn't restored navigate to the first page,
// configuring the new page by passing required information as a navigation
// parameter
if (!rootFrame.Navigate(typeof(MainPage), args.Arguments))
{
throw new Exception("Failed to create initial page");
}
}
// Ensure the current window is active
Window.Current.Activate();
edit2: some more info about my setup:
Visual Studio 2013 RC
Windows 8.1 RTM
SQLite for Windows Runtime 3.8.0.2
sqlite-net 1.0.7
Your project has its build mode currently set to Any CPU, what is the default. Because the SqLite assembly is not build as AnyCPU you need to set your build mode to X86 and add the X86 SqLite reference.
When deploying your app you also need to create 3 packages instead of 1 AnyCPU package.
Because your project is AnyCPU you get the error message when trying to add the x86, x86 is not valid for AnyCPU.
UPDATE
I tried to replicate your problem. I installed the SQLite for Windows Runtime for Visual Studio Ultimate 2012, after that I created a Windows Store Project, then added the SqLite reference after that I added sqlite-net and last I added your code for DB creation.
I modified the code a little bit (path & tables). But my code gives no error at all.
I did not need to reference the SqLite assemblies myself. Because by installing the extension into Visual Studio you get the reference in your extension list (still need to select it, just not add the dlls):
But still like I said in my first answer, you need to set your build mode to something else than 'Any CPU'
My example is on my skydrive (when testing set configuration to x86).
UPDATE 2
Db path:
var dbPath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalFolder.Path, "db.sqlite");
var db = new SQLite.SQLiteConnection(dbPath);
Related
I'm using this section of this official MSDN tutorial: Use a SQLite database in a UWP app but I'm getting the following error:
REMARK: There are many online posts related (or similar) to this issue but none seems to have a solution. Most of these posts are a few years old so I thought this issue would have been resolved by now. Moreover, the above mentioned tutorial is using .NET Standard Class library project, as well. And the online posts regarding the issue do not have .NET Standard involved. So, I was wondering if the issue is caused by the use of .NET Standard library. Regardless, a solution will be greatly appreciated.
SQLite Error 14: 'unable to open database file'
Error occurs at line db.Open() of this code:
public static void InitializeDatabase()
{
using (SqliteConnection db =
new SqliteConnection("Filename=sqliteSample.db"))
{
db.Open();
String tableCommand = "CREATE TABLE IF NOT " +
"EXISTS MyTable (Primary_Key INTEGER PRIMARY KEY, " +
"Text_Entry NVARCHAR(2048) NULL)";
SqliteCommand createTable = new SqliteCommand(tableCommand, db);
createTable.ExecuteReader();
}
}
NOTES:
The line just below the above code reads: This code creates the SQLite database and stores it in the application's local data store. That means the app should have access to that local data store.
I'm using latest version 16.3.5 of VS2019 on Windows 10. The target version on the project is selected as Windows 10 1903 and min version as Windows 10 1903
UPDATE
This similar official 3 years old sample works fine. So, the problem seems to be related to newer versions of .NET Core. But I need to use latest version of .NET Core for other features my app is using that are not available in the older versions.
I also tried this similar old tutorial, but it did not on new version of .NET Core work either - giving exact same error.
The old problem reported in 2016 here to Microsoft seems to have resurfaced again with the new version of .NET Core.
This is a misunderstanding, SqliteConnection db = new SqliteConnection("Filename=sqliteSample.db") can not create a Sqlite file, but access the existing Sqlite database file through the path.
So you need to create a valid sqliteSample.db file and place it in the root directory of the UWP project. Select the content in the Properties -> Build operation to ensure it will be loaded into the application directory.
Update
Please create the sqliteSample.db file in LocalFolder first.
await ApplicationData.Current.LocalFolder.CreateFileAsync("sqliteSample.db", CreationCollisionOption.OpenIfExists);
Then use the path to access the database file
string path = Path.Combine(ApplicationData.Current.LocalFolder.Path, "sqliteSample.db");
using (SqliteConnection db =
new SqliteConnection($"Filename={path}"))
{
// ...
}
Best regards.
We have a Xamarin.Forms project that needed to use the sqlite local db to store date. EF Core's sqlite library was used to set this up and by different developers from different PCs (vs 2019). Initially, it was used with the Database.EnsureCreated() function and later with ef core's migrations. All went smooth for more than a month.
Last week all of a sudden the android app wouldn't start on any one's PC due to some error with sqlite. It showed the following error:
Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR)
I spent a while trying all kinds of fixes and rollbacks thinking it was an issue with the code. This included the following:
Deleted obj and bin folders, cleaned and rebuilt for all below steps.
Downgraded the version of ef to 2.2.3 (the version we started with)
Rolled back to git commits up to a week back
Upgraded the versions of dependencies of ef core
Removed the past few migrations
Downgraded xamarin forms to 3.6.x
After trying the above and several other fixes, finally upgrading the versions of java and android SDK worked last Friday (on all PCs). Once this fix worked everything went smooth that day. On Tuesday once again the issue was back (no library updates or code changes). A deeper look at EF Cores logging shows that it crashes the moment it attempts to connect to a db.
The issue can be replicated on the android devices but not the emulators. I am not sure if there is some new permission in android we need to request for.
I finally created a new xamarin forms project with sqlite setup. I used the pcl library and ef core. I still found the same error.
Here is the git hub that replicates the issue https://github.com/neville-nazerane/xamarin-site
Update
Just something i noticed. eariler my database file was named "main.db". Now no matter what i change this file name to or no matter what variables i change. it always shows database name as "main" in logs. Not sure if changing the db name would fix the issue. However, never found a way to change this db name. I tried different connection strings, it just said "database" and "db" were unknown keys
Update
Steps to replicate:
using (var db = new AppDbContext())
{
db.Add(new Person {
Age = 55,
Name = "Neville"
});
db.SaveChanges();
Person[] alldata = db.People.ToArray();
}
The definitions of Person and AppDbContext are quite obvious. So, with the spirit of not making the question too long, I am not posting it here. However, if required I can post them too.
This is a bug with the Xamarin.Forms and Mono.
It was detected since a couple of months ago, it was fixed but then there was some regression (with VS 2019 v16.1).
Even with the latest release (v16.1.2) the bug still happens, so we need to wait for a fix.
Sources:
https://github.com/mono/mono/issues/14170
https://github.com/xamarin/xamarin-android/issues/3112
https://github.com/xamarin/xamarin-android/issues/2920
Due to slight differences of the particular file systems on the native side, I would suggest creating an interface to handle the actual database file handling on the native application level.
So here is how I implemented SQLite using the nuget package SQLite.Net-PCL:
In the shared project, create a new interface, for instance FileHandler.cs
public interface IFileHandler
{
SQLite.SQLiteConnection GetDbConnection();
}
You may want to extend that with more methods to save or retrieve various files, but for now we will just have the GetDbConnection Method to retrieve a working SQLite Connection.
Now in your Android implementation, we add the native implementation to that interface:
Create a new class called FileHandler.cs in your android project:
[assembly: Dependency(typeof(FileHandler))]
namespace YourProjectName.Droid
{
public class FileHandler : IFileHandler
{
public SQLite.SQLiteConnection GetDbConnection()
{
string sqliteFilename = "YourDbName.db3";
string path = Path.Combine(GetPersonalPath(), sqliteFilename);
SQLiteConnectionString connStr = new SQLiteConnectionString(path, true);
SQLiteConnectionWithLock connection = new SQLiteConnectionWithLock(connStr, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.NoMutex);
return connection;
}
private string GetPersonalPath()
{
return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
}
}
}
Now back again in your shared code you can access that connection with the following code:
using (SQLiteConnection connection = DependencyService.Get<IFileHandler>().GetDbConnection())
{
// Do whatever you want to do with the database connection
}
Alright mate, I don't understand what issue you are facing. It might be an issue with your machine, I'd suggest using another computer/laptop.
I took the exact code that you shared on the Github. I was able to build it on my Mac computer in VS 2019 and installed the application in debug mode on my phone. I was able to add a date successfully, as you can see in the picture, and I placed an Exception Catchpoint and faced no exceptions.
I then proceeded to add another entry with the same details and it errored out with the message that you can see here
I would also suggest using Xamarin Profiler or any other Android logger to see the Stack Trace that you aren't able to see in your application output. It will give you details of the error, that you can share here for us to understand better.
I've got a Xamarin.Forms app and when I try to build the Android app I get the following compile time error:
Target _XamarinAndroidBuildAarRestore:
/packages/Xamarin.Build.Download.0.4.9/build/Xamarin.Build.Download.targets(120,4):
error MSB4064: The "VsInstallRoot" parameter is not supported by the "XamarinBuildAndroidAarRestore" task. Verify the parameter exists on the task, and it is a settable public instance property.
/packages/Xamarin.Build.Download.0.4.9/build/Xamarin.Build.Download.targets(114,3):
error MSB4063: The "XamarinBuildAndroidAarRestore" task could not be initialized with its input parameters.
The iOS app builds fine.
I'm using Visual Studio for Mac (version 7.4.1 build 48).
I was able to get this error to go away by deleting the packages, bin, and obj folders from my solution as referenced in this Xamarin Forum:
https://forums.xamarin.com/discussion/96703/the-user7zippath-parameter-is-not-supported
EDIT: I found a way to get it to work locally, but on Azure I still get System.IO.FileNotFoundException on that assembly.
My question might seem like a duplicate to this question here. But it is slightly different, I have already tried that solution and it did not work. Here are the details.
I have an ASP.NET MVC App that has a Reference added to a third party CLR DLL. That third-party DLL requires a native DLL which it invokes. Now if I had control over where the Shadow Copying occurs and what is copied, I would be in paradise. The Shadow Copying misses copying that native DLL despite it's Build Action set as Content and Copy To Output Dir set as Copy Always.
So I searched internet and ran into this discussion on SO, which is same as what was mentioned earlier. I tried adding the code that sets the PATH Environment Variable inside Application_Init and Application_Start of Global.asax, I set the breakpoints in both the methods and to my surprise I get the ASP.NET Error Page before it even hits the breakpoint. This leads me to believe that the referenced assembly at the time of binding hits the native DLL and invokes it. What can I do? Can I delay the reference binding somehow?
EDIT: Yes we can, I opened the Referenced DLL's code which was written in Managed C++, I adjusted the linker setting to Delay Load the Native DLL and now my Application_Start executes first. Yayy! but that does not solve the same problem I am having on Azure
Here is the test solution with DLLs
Here is the source code for the Native DLL
Here is the source code for the Referenced Assembly that uses the Native DLL
To download the Native DLL distribution, Go to their distribution page, choose the windows archive with the bitness you desire (I am using 32-bit), and you will find amzi.dll inside APIs/bin directory.
Actual problem was the wrapper DLL not recognized on Azure server because of lack of support of earlier frameworks and toolsets, as well as Debug CRT.
I used XDT/Application_Start to set the PATH environment variable to include the location of my native DLL
I upgraded my Managed C++ Wrapper DLL to use Toolset 14.0 and .NET 4.6.2
Used Linker Setting of /DELAYLOAD on Managed C++ Wrapper DLL
After downloaded the DLLs and source code which you provided, I found that the native DLL depends on x64 platform. Firstly, we need to change the Platform property of our web app to x64 using Azure portal. If the platform button is disabled, you need to scale up your web app plan to Basic level plan or higher level.
In addition, the original path may end with “;”, so we need to check whether it contains “;” and append right content to it. Code below is for your reference.
string path = Environment.GetEnvironmentVariable("PATH");
Trace.TraceError(path);
string binDir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Bin");
Trace.TraceError(binDir);
if (path.EndsWith(";"))
{
Environment.SetEnvironmentVariable("PATH", path + binDir);
}
else
{
Environment.SetEnvironmentVariable("PATH", path + ";" + binDir);
}
To test whether the path is set successfully, you could add a page to test it.
public ActionResult GetPath()
{
string path = Environment.GetEnvironmentVariable("PATH");
return Content(path);
}
After path is set, the native DLL can be load successfully on my side.
On my end I added a throw new ApplicationException("Test") at the beginning of Application_Start and instead of getting my test exception, I was getting the DLL load error.
It means the setting path code will not executed. To fix it, you could remove the native DLL reference from your web application. Now your application could work fine and set the path environment variable. Then you could add the native DLL reference back.
Another way to do it is that we could create a webjobs and set the path environment variable in webjobs and deploy this webjobs before deploying your web application.
I am using 32-bit distributions, my native dlls depends on x86/32-bit.
If you use 32-bit distributions and the platform targets of your CLR DLL and your web application are set to "x86 or Any CPU", you won't need to change platform to x64 in web app. Please change it back to x86.
I'd like to use a piece of Windows 10 specific UWP API (specifically, the Windows.Graphics.Printing3D stuff) in an ASP.NET code-behind DLL. Is there any way to do so?
While looking for a .NET-only resolution to this one, I've found a moderately clean way - a Win32/64 C++ DLL that would consume UWP API and present a COM- or P/Invoke-based interface to .NET.
Create a regular Win32 DLL. Build an interface for .NET to consume - exported functions or objects, depends. In my case, a single exported function will do. In the project's C/C++ settings, make the following changes:
Under General, set Consume Windows Runtime Extensions to Yes.
Under General, set Additional #using Directories to: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcpackages;C:\Program Files (x86)\Windows Kits\10\UnionMetadata (assuming Visual Studio 2015)
Under Code Generation, set Enable Minimal Rebuild to No (it's only Yes for Debug, not for Release).
Then instantiate and use UWP components in the DLL in the usual C++/CX manner, like you would in a Store app, via using namespace Windows::... and ref new.
In this approach, you lose bitness agnosticism; an unmanaged DLL can't be "Any CPU". You win some, you lose some. Also, the site will not run without the Visual C++ redistributable package on the system. On the other hand, it may run faster than a .NET app; less managed/native boundary crossings.
Inspiration: "Using C++/CX in Desktop apps" by Pavel Y.
Open the project file as XML, and paste the following line under the first <PropertyGroup>:
<TargetPlatformVersion>10.0</TargetPlatformVersion>
Once you do that, the Add reference dialog will include UWP libraries, and the file type options in the "Browse..." dialog there will include .winmd.
Load the project, do Add reference/Browse, locate C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Windows.winmd, add that.
There are some helpful extension methods in the managed assembly System.Runtime.WindowsRuntime (e. g. IBuffer.AsStream()), but for some reason, it's not listed under Assemblies. To reference it, you'd need to edit the project file directly, and under the first <ItemGroup>, add the following:
<Reference Include="System.Runtime.WindowsRuntime" />
Unlike the guide states, you don't need to change the compilation target to x86 or x64; leave AnyCPU be.
For desktop .NET applications, this is sufficient. For ASP.NET, however, there's a catch. The way the ASP.NET runtime sets up its AppDomains not compatible with UWP. It's probably a bug deep down, but I've reported it, and a Microsoft rep said the whole thing was not a supported scenario to begin with.
Anyway, you have to change the LoaderOptimization policy of the AppDomain to SingleDomain. The quickest way to do so is via abusing a private method of AppDomain:
AppDomain ad = AppDomain.CurrentDomain;
MethodInfo mi = ad.GetType().GetMethod("SetupLoaderOptimization", BindingFlags.Instance | BindingFlags.NonPublic);
mi.Invoke(ad, new object[] { LoaderOptimization.SingleDomain });
A good place to do that would be in the app startup code.
A slightly less dangerous approach would involve creating a new AppDomain, which would inherit all setup properties from the current one but LoaderOptimization, which will be set to SingleDomain, and running the UWP dependent code in that domain. Like this:
AppDomain CreateUnsharingDomain()
{
AppDomain cad = AppDomain.CurrentDomain;
AppDomainSetup cads = cad.SetupInformation;
return AppDomain.CreateDomain("Dummy", cad.Evidence,
new AppDomainSetup
{
ApplicationName = cads.ApplicationName,
ApplicationBase = cads.ApplicationBase,
DynamicBase = cads.DynamicBase,
CachePath = cads.CachePath,
PrivateBinPath = cads.PrivateBinPath,
ShadowCopyDirectories = cads.ShadowCopyDirectories,
ShadowCopyFiles = cads.ShadowCopyFiles,
ApplicationTrust = cads.ApplicationTrust,
LoaderOptimization = LoaderOptimization.SingleDomain
});
//Not sure which other properties to copy...
}
CreateUnsharingDomain().DoCallBack(MyUWPDependentMethod);
Again, it would make sense to create the domain once and cache it for the app lifetime.
This approach might be faster than the one with the monkey-patched AppDomain. The MultiDomain optimization exists for a reason; if you leave most of the Web code in a MultiDomain world, the optimization will do its work as intended.
Inspiration: "Walkthrough: Using WinRT libraries from a Windows Desktop application" by David Moore.