MvvmCross - Windows Phone 8 + SQLite - Could not open database file - sqlite

I am using MvvmCross to create Android, WPF and Windows Phone 8/8.1 apps. I've gotten SQLite working fine in the WPF and Android apps.
With the Windows Phone app, I am running into an issue when calling Create() on the SQLite database file.
The first time this is called, the create and open work just fine, but when the create() is called a second time it always fails.
Code:
ISQLiteConnection db = factory.Create("filename.sql");
db.Close();
Error:
"Could not open database file: filename.sql (CannotOpen)"
Stack:
at SQLite.SQLiteConnection..ctor(String databasePath, Boolean storeDateTimeAsTicks)
at Cirrious.MvvmCross.Plugins.Sqlite.WindowsPhone.MvxWindowsPhoneSQLiteConnectionFactory.Create(String address)
at MvvmCrossPOC.Core.Services.MetadataService.OpenDatabase()
I followed this article, and others with similar steps, and added the MvvmCross SQLite Plugin (v3.5 - Install-Package MvvmCross.HotTuna.Plugin.SQLite), but the error remained.
WP8 SQLite error: The specified module could not be found
Any thoughts on how to move forward?
Code Sample:
public MetadataService(ISQLiteConnectionFactory SQLiteConnectionFactory)
{
factory = SQLiteConnectionFactory;
}
public List<Platform> GetPlatformCollection()
{
db = factory.Create(METADATA_REPO_NAME);
try
{
return db.Table<Platform>().ToList();
}
finally
{
db.Close();
}
}

Arg! Hours to figure out this was all me writing the code incorrectly.
Remember: Services are Singletons...so, you don't have to open and close the database every time you use it!
Figured that out after finding Stuart's SQLite example: KittensDB
Not sure why I didn't see this issue on any other platforms...
Working Code Sample
public MetadataService(ISQLiteConnectionFactory factory)
{
//Get the connection
db = factory.Create(METADATA_REPO_NAME);
db.CreateTable<PlatformStorage>();
db.CreateTable<DashboardStorage>();
}
public List<Platform> GetPlatformCollection()
{
return db.Table<Platform>().ToList();
}

Related

Realm doesn’t work with xUnite and .net core

I’m having issues running realm with xUnite and Net core. Here is a very simple test that I want to run
public class UnitTest1
{
[Scenario]
public void Test1()
{
var realm = Realm.GetInstance(new InMemoryConfiguration("Test123"));
realm.Write(() =>
{
realm.Add(new Product());
});
var test = realm.All<Product>().First();
realm.Write(() => realm.RemoveAll());
}
}
I get different exceptions on different machines (Windows & Mac) on line where I try to create a Realm instace with InMemoryConfiguration.
On Mac I get the following exception
libc++abi.dylib: terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.
On Windows I get the following exception when running
ERROR Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. at
System.Net.Sockets.NetworkStream.Read(Span1 destination) at
System.Net.Sockets.NetworkStream.ReadByte() at
System.IO.BinaryReader.ReadByte() at
System.IO.BinaryReader.Read7BitEncodedInt() at
System.IO.BinaryReader.ReadString() at
Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.LengthPrefixCommunicationChannel.NotifyDataAvailable() at
Microsoft.VisualStudio.TestPlatform.CommunicationUtilities.TcpClientExtensions.MessageLoopAsync(TcpClient client, ICommunicationChannel channel, Action1 errorHandler, CancellationToken cancellationToken) Source: System.Net.Sockets HResult: -2146232800 Inner Exception: An existing connection was forcibly closed by the remote host HResult: -2147467259
I’m using Realm 3.3.0 and xUnit 2.4.1
I’ve tried downgrading to Realm 2.2.0, and it didn’t work either.
The solution to this problem was found in this Github post
The piece of code from that helped me to solve the issue
Realm GetInstanceWithoutCapturingContext(RealmConfiguration config)
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(null);
Realm realm = null;
try
{
realm = Realm.GetInstance(config);
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
return realm;
}
Though it took a while for me to apply this to my solution.
First and foremost, instead of just setting the context to null I am using Nito.AsyncEx.AsyncContext. Because otherwise automatic changes will not be propagated through threads, as realm needs a non-null SynchronizationContext for that feature to work. So, in my case the method looks something like this
public class MockRealmFactory : IRealmFactory
{
private readonly SynchronizationContext _synchronizationContext;
private readonly string _defaultDatabaseId;
public MockRealmFactory()
{
_synchronizationContext = new AsyncContext().SynchronizationContext;
_defaultDatabaseId = Guid.NewGuid().ToString();
}
public Realm GetRealmWithPath(string realmDbPath)
{
var context = SynchronizationContext.Current;
SynchronizationContext.SetSynchronizationContext(_synchronizationContext);
Realm realm;
try
{
realm = Realm.GetInstance(new InMemoryConfiguration(realmDbPath));
}
finally
{
SynchronizationContext.SetSynchronizationContext(context);
}
return realm;
}
}
Further, this fixed a lot of failing unit tests. But I was still receiving that same exception - Realm accessed from incorrect thread. And I had no clue why, cause everything was set correctly. Then I found that the tests that were failing were related to methods where I was using async realm api, in particular realm.WriteAsync. After some more digging I found the following lines in the realm documentation.
It is not a problem if you have set SynchronisationContext.Current but
it will cause WriteAsync to dispatch again on the thread pool, which
may create another worker thread. So, if you are using Current in your
threads, consider calling just Write instead of WriteAsync.
In my code there was no direct need of using the async API. I removed and replaced with sync Write and all the tests became green again! I guess if I find myself in a situation that I do need to use the async API because of some kind of bulk insertions, I'd either mock that specific API, or replace with my own background thread using Task.Run instead of using Realm's version.

Publishing web app to Azure Websites Staging deployment slot fails with webjob

I just created a new deployment slot for my app, imported the publishing profile to Visual Studio, but after deployment I get this error message:
Error 8: An error occurred while creating the WebJob schedule: No website could be found which matches the WebSiteName [myapp__staging] and WebSiteUrl [http://myapp-staging.azurewebsites.net] supplied.
I have 2 webjobs, a continuous and a scheduled webjob.
I already signed in to the correct Azure account, as stated by this answer.
Will I need to set something else up in order to deploy my app to a staging Deployment Slot with webjobs?
My app is using ASP.NET, if it makes a difference?
There are a few quirks when using the Azure Scheduler. The recommendation is to use the new CRON support instead. You can learn more about it here and here.
Jeff,
As David suggested, you can/should migrate to the new CRON support. Here's an example. The WebJob will be deployed as a continuous WebJob.
Keep in mind that in order to use this you need to install the WebJobs package and extensions that are currently a prerelease. You can get them on Nuget.
Install-Package Microsoft.Azure.WebJobs -Pre
Install-Package Microsoft.Azure.WebJobs.Extensions -Pre
Also, as David suggested if you're not using the WebJobs SDK, you can also run this using a settings.job file. He provided an example here.
Program.cs
static void Main()
{
//Set up DI (In case you're using an IOC container)
var module = new CustomModule();
var kernel = new StandardKernel(module);
//Configure JobHost
var storageConnectionString = "your_connection_string";
var config = new JobHostConfiguration(storageConnectionString) { JobActivator = new JobActivator(kernel) };
config.UseTimers(); //Use this to use the CRON expression.
//Pass configuration to JobJost
var host = new JobHost(config);
// The following code ensures that the WebJob will be running continuously
host.RunAndBlock();
}
Function.cs
public class Functions
{
public void YourMethodName([TimerTrigger("00:05:00")] TimerInfo timerInfo, TextWriter log)
{
//This Job runs every 5 minutes.
//Do work here.
}
}
You can change the schedule in the TimerTrigger attribute.
UPDATE Added the webjob-publish-settings.json file
Here's an example of the webjob-publiss-settings.json
{
"$schema": "http://schemastore.org/schemas/json/webjob-publish-settings.json",
"webJobName": "YourWebJobName",
"startTime": null,
"endTime": null,
"jobRecurrenceFrequency": null,
"interval": null,
"runMode": "Continuous"
}

ASP.NET 5, EF 7 and SQLite - SQLite Error 1: 'no such table: Blog'

I followed the Getting Started on ASP.NET 5 guide about Entity Framework 7 and I replaced MicrosoftSqlServer with Sqlite, the only difference in the code is in Startup.cs:
services.AddEntityFramework()
.AddSqlite()
.AddDbContext<BloggingContext>(options => options.UseSqlite("Filename=db.db"));
When I run the website and navigate to /Blogs, I get an error:
Microsoft.Data.Sqlite.SqliteException was unhandled by user code
ErrorCode=-2147467259 HResult=-2147467259 Message=SQLite Error 1:
'no such table: Blog' Source=Microsoft.Data.Sqlite
SqliteErrorCode=1 StackTrace:
at Microsoft.Data.Sqlite.Interop.MarshalEx.ThrowExceptionForRC(Int32 rc,
Sqlite3Handle db)
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior
behavior)
at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReader(CommandBehavior
behavior)
at System.Data.Common.DbCommand.ExecuteReader()
at Microsoft.Data.Entity.Query.Internal.QueryingEnumerable.Enumerator.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at System.Linq.Enumerable.d__1`2.MoveNext()
at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
at Microsoft.Data.Entity.Query.LinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at EFGetStarted.AspNet5.Controllers.BlogsController.Index() in d:\arthur\documents\visual studio
2015\Projects\EFGetStarted.AspNet5\src\EFGetStarted.AspNet5\Controllers\BlogsController.cs:regel
18 InnerException:
I understand this as if there is no table called 'Blog', but when I open the .db file in DB Browser for SQLite, there actually is a table called 'Blog':
Does SQLite require other changes in the code, or is this an error in the SQLite connector for Entity Framework?
It is very likely the database actually being opened by EF is not the file you are opening in DB Browser. SQLite use the process current working directory, which if launched in IIS or other servers, can be a different folder than your source code directory. (See issues https://github.com/aspnet/Microsoft.Data.Sqlite/issues/132 and https://github.com/aspnet/Microsoft.Data.Sqlite/issues/55).
To ensure your db file is in the right place, use an absolute path. Example:
public class Startup
{
private IApplicationEnvironment _appEnv;
public Startup(IApplicationEnvironment appEnv)
{
_appEnv = appEnv;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFramework()
.AddSqlite()
.AddDbContext<MyContext>(
options => { options.UseSqlite($"Data Source={_appEnv.ApplicationBasePath}/data.db"); });
}
}
I did this and was still having trouble loading the database. I added the following code in the constructor for the database context:
Database.EnsureCreated();
Now my context file looks like this:
It created a new database on my new Azure hosting site, so if you have a lot of existing data to migrate, this won't work. It worked for me so figured I'd share.
Taken from EF Core documentation...
Run from Visual Studio
To run this sample from Visual Studio, you must set the working
directory manually to be the root of the project. Ifyou don't set the
working directory, the following Microsoft.Data.Sqlite.SqliteException
is thrown: SQLite Error 1: 'no such table: Blogs'.
To set the working directory:
In Solution Explorer, right click the project and then select Properties.
Select the Debug tab in the left pane.
Set Working directory to the project directory.
Save the changes.
I had this issue on netcoreapp2.0. There's a related issue that may be at fault, but I didn't want to solve it by going to a nightly build.
The solution for me was to create and pass an SqliteConnection instead of using the builder string.
So for this setup:
string id = string.Format("{0}.db", Guid.NewGuid().ToString());
var builder = new SqliteConnectionStringBuilder()
{
DataSource = id,
Mode = SqliteOpenMode.Memory,
Cache = SqliteCacheMode.Shared
};
Compose for the DI like so:
var connection = new SqliteConnection(builder.ConnectionString);
connection.Open();
connection.EnableExtensions(true);
services.AddDbContext<SomeDbContext>(options => options.UseSqlite(connection));
The error I had was using this style of init:
services.AddDbContext<SomeDbContext>(options => options.UseSqlite(builder.ConnectionString));
My scaffolding also has a one-time call to:
var dbContext = serviceScope.ServiceProvider.GetService<SomeDbContext>();
dbContext.Database.OpenConnection();
dbContext.Database.EnsureCreated();
Using this approach all my DI-instantiated copies of SomeDbContext would all point at a valid SQLite db, and that db would have auto-created schema as per my entities.
Looks like things have changed because IApplicationEnvironment has been replaced with IHostingEnvironment.
Removing IApplicationEnvironment \ IRuntimeEnvironment
public class Startup
{
private IHostingEnvironment _appHost;
public Startup(IHostingEnvironment appHost)
{
_appHost = appHost;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkSqlite()
.AddDbContext<MyContext>(
options => { options.UseSqlite($"Data Source={_appHost.ContentRootPath}/data.db"); });
}
}
I Had the same problem and I found the answer in this link:
https://www.youtube.com/watch?v=yRmMYrSROPs
Just update your database via command:
dotnet ef update database
you can set up the configuration adding;
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("Data Source = path//DatabaseName.db");
}
the example uses SQLite, but you can choose your own DB.
If you have multiple DataContexts, the EnsureCreated method will only work on the first call. See its documentation:
If the database exists and has any tables, then no action is taken
To create tables of additional DataContexts, use
RelationalDatabaseCreator databaseCreator =
(RelationalDatabaseCreator) secondDbContext.Database.GetService<IDatabaseCreator>();
databaseCreator.CreateTables();

Where is SQLite database stored in Windows phone 8.1

I have a SQLite database in my Windows phone 8.1 application. I am copying it by using this code
public async void UpDatabase()
{
bool isDatabaseExisting = false;
try
{
StorageFile storageFile = await ApplicationData.Current.LocalFolder.GetFileAsync("ComplainSys.db");
isDatabaseExisting = true;
}
catch
{
isDatabaseExisting = false;
}
if (!isDatabaseExisting)
{
StorageFile databaseFile = await Package.Current.InstalledLocation.GetFileAsync("ComplainSys.db");
await databaseFile.CopyAsync(ApplicationData.Current.LocalFolder);
}
}
I want to access that location where it is stored . When I put breakpoint and check that path and try to access that it shown this error.
How do I access that?
ApplicationData.Current.LocalFolder is the folder. But I don't really know how did you try to access the folder using the breakpoint, are you using Windows Explorer to open that folder? The path is local to phone storage, not your computer's one.
I use the other software, i think it's more good than isolated storage and don't need add external classes or same in your project... I used this: http://isostorespy.codeplex.com/downloads/get/835310
Just unzip folder and open your emulator, when emulator is opened, execute .exe and select your emulator, then u can explore local ,roaming and temp folder. Finally this software work with windows phone 8+ (8,8.1). It's too easy!
PD: If u had problems advise me, Good Luck!

can't find IfxBulkCopy in IBM.Data.Informix 2.81.0.0

Q:
My question consists of two parts:
1- I want to use the following class IfxBulkCopy to insert large amount of data but this class doesn't exist in the dll IBM.Data.Informix 2.81.0.0 how to fix this problem.?
Note : the class exist in the IBM.Data.Informix 9.0.0.2 !but i can't use this version because we use an old version of the informix.
When i use the new version i get the following exception :
Invalid argument
StackTrace = " at IBM.Data.Informix.IfxConnection.ReplaceConnectionStringParms(String szValue, IfxConnSettings& connSettings)\r\n at IBM.Data.Informix.IfxConnection.set_ConnectionString(String value)\r\n at Common.DBConnectionForInformix..ctor(String ConnectionStr...
My .cs:
public static void InsertAsBulk(DataTable dt)
{
using (IfxConnection cn = new IfxConnection(ConfigurationManager.ConnectionStrings["aa"].ToString()))
{
cn.Open();
using (IfxBulkCopy copy = new IfxBulkCopy(cn))
{
copy.ColumnMappings.Add(1, 2);
copy.ColumnMappings.Add(2, 3);
copy.ColumnMappings.Add(3, 4);
copy.ColumnMappings.Add(4, 5);
copy.ColumnMappings.Add(5, 6);
copy.ColumnMappings.Add(6, 7);
copy.DestinationTableName = "schday";
copy.WriteToServer(dt);
}
}
}
2- Is the IfxBulkCopy use the transaction concept during the insertion operation or may result inconsistent data also .
Your connection string is fine. Do you have multiple versions of driver installed? I had same problem when I installed OAT, Informix driver and Informix Client SDK on same machine.
This solved my problem:
1. Uninstallation of driver and client sdk + windows restart
2. Installation of Client SDK together with data server driver
3. Checking system PATH variable. I added
C:\Program Files\IBM Informix Client SDK\bin
C:\Program Files\IBM Informix Client SDK\bin\netf20
to system PATH. I'm not sure what was the problem, maybe just changing PATH variable (without unistallation) can fix it.

Resources