sqlite-net
sqlite-net copied to clipboard
Path is not of a legal form when swapping from sqlite-net to sqlite-net-pcl
So I have this code
private async Task LoadDatabase()
{
var filePath = Path.Combine(this.CacheDir, "data.db");
_db = new SQLiteAsyncConnection(filePath);
await _db.CreateTableAsync<MusicSheetModel>();
}
which basically is
"I:\\Repositories\\github.com\\redacted\\.debug.settings\\data.db"
or a folder under documents.
I previously used the sqlite-net package and it worked without a hitch. However, the service I am using needs the sqlite3 dll references and so I swapped to the pcl version. The pcl version however does not like the path I am giving it. The code itself did not change. I literally changed nothing but the nuget packages.
Do you have an exception stack trace?
System.AggregateException
HResult=0x80131500
Message=One or more errors occurred.
Source=Blish HUD
StackTrace:
at Blish_HUD.Modules.Module.CheckForLoaded()
at Blish_HUD.ModuleService.Update(GameTime gameTime)
at Blish_HUD.BlishHud.Update(GameTime gameTime)
at Microsoft.Xna.Framework.Game.DoUpdate(GameTime gameTime)
at Microsoft.Xna.Framework.Game.Tick()
at MonoGame.Framework.WinFormsGameWindow.TickOnIdle(Object sender, EventArgs e)
at System.Windows.Forms.Application.ThreadContext.System.Windows.Forms.UnsafeNativeMethods.IMsoComponent.FDoIdle(Int32 grfidlef)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at MonoGame.Framework.WinFormsGameWindow.RunLoop()
at Microsoft.Xna.Framework.Game.Run(GameRunBehavior runBehavior)
at Blish_HUD.Program.Main(String[] args)
This exception was originally thrown at this call stack:
[External Code]
Inner Exception 1:
TypeInitializationException: The type initializer for 'SQLite.SQLiteConnection' threw an exception.
Inner Exception 2:
ArgumentException: The path is not of a legal form.
Hmmm. That wasn't as informative as I hoped. :-(
The main difference between sqlite-net and sqlite-net-pcl is that the latter uses SQLitePCLRaw (which I maintain) under the hood. The exception appears to be one thrown by somewhere in System.IO.Path, but I don't know if the offending call is in my code or in sqlite-net.
Can't you compare it to the other package?
The sqlite-net package works without a hitch. Only the sqlite-net-pcl version does this.
Any ideas to work around this? I am thinking going back to the sqlite-net package and also referencing SQLite 3.0 from https://www.nuget.org/packages/SQLite/
Both sqlite-net and sqlite-net-pcl are based on the same code, here in this repo, maintained by the same person, which is not me. I have never used either library. I only maintain the SQLitePCLRaw library. sqlite-net-pcl is simply a version of sqlite-net which uses my library instead of its own pinvoke layer.
I remain curious about what is causing the exception you see, which is why I asked for the stack trace. But the stack trace I need is the one from the inner exception, not the AggregateException. If you can provide that, I may be able to see what is going wrong.
Ah misunderstood.
Here's the inner exception stacktrace:
at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
at System.IO.Path.InternalGetDirectoryName(String path)
at SQLitePCL.NativeLibrary.MakePossibilitiesFor(String basename, Assembly assy, Int32 flags, LibSuffix suffix)
at SQLitePCL.NativeLibrary.MyLoad(String basename, Assembly assy, Int32 flags, Action`1 log)
at SQLitePCL.NativeLibrary.Load(String libraryName, Assembly assy, Int32 flags)
at SQLitePCL.Batteries_V2.MakeDynamic(String name, Int32 flags)
at SQLitePCL.Batteries_V2.DoDynamic_cdecl(String name, Int32 flags)
at SQLite.SQLiteConnection..cctor()
at SQLite.SQLiteConnection..ctor(SQLiteConnectionString connectionString)
at SQLite.SQLiteConnectionPool.Entry..ctor(SQLiteConnectionString connectionString)
at SQLite.SQLiteConnectionPool.GetConnectionAndTransactionLock(SQLiteConnectionString connectionString, Object& transactionLock)
at SQLite.SQLiteAsyncConnection.<>c__DisplayClass33_0`1.<WriteAsync>b__0()
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Nekres.Musician.UI.MusicSheetService.<LoadDatabase>d__13.MoveNext() in I:\Repositories\github.com\Blish-HUD-Musician\Musician Module\UI\MusicSheetService.cs:line 44
OK, the stack trace is helpful, thanks. The exception occurs from a call in my code, but I don't yet see why. I'll take a closer look and see if I can figure it out. I've never seen this particular problem before.
Some other info: The assembly and all the dependencies including sqlite-net-pcl of my project are being loaded into another app as a module.
Your latest comment may be quite relevant. I was just looking at my code for MakePossibilitiesFor
. It is trying to find the instance of the native SQLite library. The code it uses is basically equivalent to this:
var assembly = typeof(SQLitePCL.raw).Assembly;
var dir = System.IO.Path.GetDirectoryName(assembly .Location);
And apparently assembly .Location
returns a string that GetDirectoryName()
does not like. Which might happen if the assembly
object is special because it was loaded differently?
You could verify this by putting the two lines above somewhere very early in your initialization, maybe just before you would be calling SQLite stuff, and see if you get the same exception. I wonder what assembly.Location
is.
Note that if my guess is correct, then the path exception you saw has nothing to do with, the path of your sqlite database file.
Hi @ericsink / @agaertner - I seem to have the same issue like yours. Have you guys got that issue solved? If so mind to brief how did you solve it?
`System.TypeInitializationException: The type initializer for 'SQLite.SQLiteConnection' threw an exception. ---> System.ArgumentException: The path is not of a legal form.
at System.IO.Path.LegacyNormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
at System.IO.Path.InternalGetDirectoryName(String path)
at SQLitePCL.NativeLibrary.MakePossibilitiesFor(String basename, Assembly assy, Int32 flags, LibSuffix suffix)
at SQLitePCL.NativeLibrary.MyLoad(String basename, Assembly assy, Int32 flags, Action`1 log)
at SQLitePCL.NativeLibrary.Load(String libraryName, Assembly assy, Int32 flags)
at SQLitePCL.Batteries_V2.MakeDynamic(String name, Int32 flags)
at SQLitePCL.Batteries_V2.DoDynamic_cdecl(String name, Int32 flags)
at SQLite.SQLiteConnection..cctor()
--- End of inner exception stack trace ---
`at SQLite.SQLiteConnection..ctor(SQLiteConnectionString connectionString)
at SQLite.SQLiteConnectionPool.Entry..ctor(SQLiteConnectionString connectionString)
at SQLite.SQLiteConnectionPool.GetConnectionAndTransactionLock(SQLiteConnectionString connectionString, Object& transactionLock)
at SQLite.SQLiteAsyncConnection.<>c__DisplayClass33_0`1.<WriteAsync>b__0()
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()'
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at Code.General._abcdef.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.QueueUserWorkItemCallback.System.Threading.IThreadPoolWorkItem.ExecuteWorkItem()
at System.Threading.ThreadPoolWorkQueue.Dispatch()`
I never got a reply to my previous comment, but I'd still be curious if something about the configuration is causing Assembly.Location to be something unexpected.
Unfortunately I swapped over to LiteDB hence I couldn't further verify it. But I would assume since my stuff is bundled in an archive and loaded into another project as a module dll as well as its dependencies it might be that some directory identification issues are at fault.
Just wasted 2 hours to get it work. This package does not work with Costura.Fody or anything else that embeds references as resources.
Just wasted 2 hours to get it work. This package does not work with Costura.Fody or anything else that embeds references as resources.
Yes I can confirm you have to exclude all sqlite dlls from Costura.Fody build action. You can still use Costura.Fody in your project, but you just can't bundle the sqlite libraries:
In the FodyWeavers.xml
<?xml version="1.0" encoding="utf-8"?>
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<Costura>
<ExcludeAssemblies>
sqlite*
</ExcludeAssemblies>
</Costura>
</Weavers>
@ericsink I'm facing the same issue and hope you can provide some insight. Assembly.Location
returns an empty string when the assembly is loaded using Assembly.Load
- that's what triggers the previously mentioned error:
ArgumentException: The path is not of a legal form.
I've tried to use SQLitePCL.raw.SetProvider(new SQLitePCL.SQLite3Provider_e_sqlite3());
instead of a bundle and can't get it to work due to the error below, which seemed to be caused by using packages.config
, but after migrating to PackageReference and trying numerous different solutions the issue still persists. Some kind compatibility issue perhaps?
Unable to load DLL 'e_sqlite3': The specified module could not be found
It would be good to get a workaround for this. I did see that in the MakePossibilitiesFor
method it will use Assembly.GetExecutingAssembly().CodeBase
instead of Assembly.Location
, but I don't understand when exactly this happens.
Details .NET Framework 4.7.2 Class Library sqlite-net-base - 1.8.116 SQLitePCLRaw.core - 2.1.8 SQLitePCLRaw.lib.e_sqlite3 - 2.1.8 SQLitePCLRaw.provider.e_sqlite3
If you're using SetProvider with provider.e_sqlite3, the error indicates that the native e_sqlite3.dll didn't get copied into your build output directory. When using .NET Framework, modern versions of the .NET SDK handle this differently than how things worked in the old days. Try adding a RuntimeIdentifier property to your csproj:
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
Managed to get it working by embedding the e_sqlite3.dll
file using Costura. Hopefully this will help anyone facing the same issue.
- The
sqlite-net-pcl
package depends on a SQLitePCLRaw bundle that usesAssembly.Location
to determine the location of thee_sqlite3.dll
assembly, which can return an empty string if the assembly referencing the package is loaded by an MEF program like Blish HUD, or according to other people when using Costura.Fody. - The
sqlite-net-base
package does not depend on the bundle and can therefore still be used together with Costura. That does mean you have to install the SQLitePCLRaw's core, provider and lib packages yourself.
This post describes how to embed the e_sqlite3.dll
file using Costura.