Windows Phone 8.1 crashing when creating a DB lock - sqlite

I have the following code which I use frequently with Android and iOS when creating apps. Simply, it creates a lock when inserting, creating or updating a table.
public class SQL
{
readonly object dbLock = new object();
const string DBClauseSyncOff = "PRAGMA SYNCHRONOUS=OFF;";
const string DBClauseVacuum = "VACUUM;";
#region Setup
public bool SetupDB()
{
lock (dbLock)
As soon as the WinPhone 8.1 app hits this lock line, an exception is thrown. As this is part of a Xam.Forms application, I call this into existence using the following
public App()
{
App.Self = this;
var netLanguage = DependencyService.Get<ILocalise>().GetCurrent();
LangResources.Culture = new CultureInfo(netLanguage);
ConnectionString = DependencyService.Get<ISQLite>().GetConnectionString();
App.Self.SQLitePlatform = DependencyService.Get<ISQLite>().GetPlatform();
DBManager = new SQL();
DBManager.SetupDB();
Nothing is being called asynchronously with the two dependency services returning as their names suggest the connection and platform in use.
The calls look like this
public string GetConnectionString()
{
var documents = ApplicationData.Current.LocalFolder.Path;
var pConnectionString = System.IO.Path.Combine(documents, "preferences.db");
var connectionString = string.Format("{0}; New=true; Version=3;PRAGMA locking_mode=NORMAL; PRAGMA journal_mode=WAL; PRAGMA cache_size=20000; PRAGMA page_size=32768; PRAGMA synchronous=off", pConnectionString);
return connectionString;
}
public ISQLitePlatform GetPlatform()
{
return new SQLite.Net.Platform.WinRT.SQLitePlatformWinRT();
}
If I comment out the SetupDB line, the app runs as I would expect. If it is left in, the app crashes with the error that it cannot create the initial display.
Is there something I need to be doing (or not doing) in order for the DB code to work on all platforms and not just Android and iOS?

Related

EPPLUS package works fine locally but returns Internal server error when deployed to azure server

I have my web api that uploads and reads an excel file from the client app and then afterwards saves the data into the database, the application works perfect on locally server but the problem comes when the application is deployed to azure server it returns error 500 internal server error therefore i don't understand why this happens and and don't know how i can track to understand what might be the cause below are my code blocks.
My Interface Class
public interface UploadExcelInterface
{
Task UploadMultipleClients(Client obj);
}
My Service Implementation
public class UploadExcelService : UploadExcelInterface
{
private readonly DbContext _connect;
private readonly IHttpContextAccessor httpContextAccessor;
public UploadExcelService(DbContext _connect, IHttpContextAccessor httpContextAccessor)
{
this._connect = _connect;
this.httpContextAccessor = httpContextAccessor;
}
public async Task UploadMultipleClients(Client obj)
{
var file = httpContextAccessor.HttpContext.Request.Form.Files[0];
if (file != null && file.Length > 0)
{
var folderName = Path.Combine("Datas", "ClientUPloads");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
var fileName = Guid.NewGuid() + ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
var fullPath = Path.Combine(pathToSave, fileName);
var clientsList = new List<Client>();
using (var fileStream = new FileStream(fullPath, FileMode.Create))
{
await file.CopyToAsync(fileStream);
FileInfo excelFile = new FileInfo(Path.Combine(pathToSave, fileName));
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (ExcelPackage package = new ExcelPackage(excelFile))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[0];
var rowcount = worksheet.Dimension.Rows;
for (int row = 2; row <= rowcount; row++)
{
var Names = (worksheet.Cells[row,2].Value ?? string.Empty).ToString().Trim();
var Address = (worksheet.Cells[row,3].Value ?? string.Empty).ToString().Trim();
var Title = (worksheet.Cells[row,4].Value ?? string.Empty).ToString().Trim();
var Product = (worksheet.Cells[row,5].Value ?? string.Empty).ToString().Trim();
var Order = (worksheet.Cells[row,6].Value ?? string.Empty).ToString().Trim();
var Email = (worksheet.Cells[row,7].Value ?? string.Empty).ToString().Trim();
var Price = (worksheet.Cells[row,8].Value ?? string.Empty).ToString().Trim();
clientsList.Add(new Client
{
Names = Names,
Address = Address,
Title = Title,
Product = Product,
Order = Order,
Email = Email,
Price = Price,
}
}
//adding clients into the database
foreach (Client client in clientsList)
{
var exist = _connect.client.Any(x => x.Email == client.Email);
if (!exist)
{
await _connect.client.AddAsync(client);
}
}
await _connect.SaveChangesAsync();
}
}
}
My Controller Class
[HttpPost]
public async Task UploadMultipleClients([FromForm] Client obj)
{
await uploadExcelInterface.UploadMultipleClients(obj);
}
}
Please any help regarding this error that am getting from the server, and addition on that is it possible to get the data from the excel file without uploading it to server if yes how? because i tried adding the file to memory stream an reading it from memory but it appers not work, any suggestions thanks.
My answer may not help you solve the problem directly, but it can locate the error step by step. After we fix the error, we should be able to solve the problem in this thread.
Suggestions
Please make sure you have inclue EPPlus library in your deploy content.
Enabling ASP.NET Core stdout log (Windows Server)
Azure App Service - Configure Detailed Error Logging
Why
After tested, I am sure azure webapp can support EPPlus. For 500 error, as we don't have a more specific error message to refer to, we can't quickly locate the problem. Following the suggested method, you will surely see some useful information.
E.g:
The class library of EPPlus was not found.
Folders such as Datas are not created.
The database connection string, the test environment and the production environment may be different.
...

App Service to EntityFramework using MSI

I'm trying to retrofit MSI to an existing app.
The original app's DbContext used only a Constructor that found a ConnectionString by the same name in the web.config.
I've modified it to use a DbConnectionFactory to inject an AccessToken.
public class AppCoreDbContext : DbContext {
public AppCoreDbContext() : this("AppCoreDbContext")
{
}
public AppCoreDbContext(string connectionStringOrName) : base( OpenDbConnectionBuilder.Create(connectionStringOrName).Result, true)
{
}
...etc...
}
The class that it is invoking looks like:
public static class OpenDbConnectionBuilder
{
public static async Task<DbConnection> CreateAsync(string connectionStringName)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
var dbConnection = DbProviderFactories
.GetFactory(connectionStringSettings.ProviderName)
.CreateConnection();
dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
await AttachAccessTokenToDbConnection(dbConnection);
// Think DbContext will open it when first used.
//await dbConnection.OpenAsync();
return dbConnection;
}
static async Task AttachAccessTokenToDbConnection(IDbConnection dbConnection)
{
SqlConnection sqlConnection = dbConnection as SqlConnection;
if (sqlConnection == null)
{
return;
}
string msiEndpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
if (string.IsNullOrEmpty(msiEndpoint))
{
return;
}
var msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET");
if (string.IsNullOrEmpty(msiSecret))
{
return;
}
string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
sqlConnection.AccessToken = accessToken;
}
}
Which invokes
// Refer to: https://winterdom.com/2017/10/19/azure-sql-auth-with-msi
public static class AppCoreDbContextMSITokenFactory
{
private const String azureSqlResource = "https://database.windows.net/";
public static async Task<String> GetAzureSqlResourceTokenAsync()
{
var provider = new AzureServiceTokenProvider();
var result = await provider.GetAccessTokenAsync(azureSqlResource);
return result;
}
}
The result of the above is that when tracking it with a debugger, it gets to
var result = await provider.GetAccessTokenAsync(azureSqlResource);
then hangs for ever.
Note: I'm working on a personal machine, not joined to the organisation domain -- but my personal MSA has been invited to the organisation's domain.
Admittedly, I've taken a hiatus from development for a couple of years, and the hang is probably due to having made a mistake around await (always been rough on understanding that implicitly)... but while trying to figure that out, and the documentation is pretty sparse, would appreciate feedback as to whether the above was the intended approach for using MSI.
I'm wondering:
When deploying to Azure, we can tell the ARM to create the Identity -- when developing, how do we tell the local machine to use MSI?
If on the dev machine the connection string is to a local db, and I create and add the token anyway, will it ignore it, or raise an exception.
This is a bit beyond the scope of discussing MSI, but I've never before created a dbConnection to use within a DbContext. Does anyone know the pros/cons of the DbContext 'owning' the connection? I'm assuming that it would be wiser to own & close the connection when the dbcontext is closed.
Basically...this is all new, so would appreciate any advice on getting this working -- the concept of being able to deploy without secrets would be awesome and would really like to get this demo working.
Thanks very much!
Hello user9314395: Managed Service Identity only works with resources running on Azure. While we don't support the local development scenario, you might consider looking into using the following (preview) library: https://learn.microsoft.com/en-us/azure/key-vault/service-to-service-authentication

sqlite-pcl database initialization in android platform

I have a very strange case using sqlite-pcl in android platform ... I have one class for database which is inherited from SQLiteConnection, I use personal folder for my db, in constructor I have one check for existence, but often when I start application again , without deleting any files, it return false...
public class ScannifyDatabase : SQLiteConnection
{
public static string DBPath
{
get
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return System.IO.Path.Combine(path, "Scaniff.db3");
}
}
public ScannifyDatabase(string path)
: base(new SQLitePlatformAndroid(),path)
{
if (!TableExists())
{
this.CreateTable<DocumentType>();
InitData();
}
}
private bool TableExists()
{
// return this.TableExists();
const string cmdText = "SELECT name FROM sqlite_master WHERE type='table' AND name=?";
var cmd = this.CreateCommand(cmdText, typeof(DocumentType).Name);
var res = !string.IsNullOrEmpty(cmd.ExecuteScalar<string>());
return res;
}
}
what the problem is?
In Xamarin Studio, under Preferences --> Android, be sure that you have "Preserve data/cache between application deploys" checked. There is a similar setting in Visual Studio.

How to properly sync Xamarin iOS Sqlite using Azure Mobile Services

In my Xamarin iOS PCL app I'm trying to insert a record into my local Sqlite table, have it synced via Azure Mobile Services, and then read it back.
Here is the code:
private IMobileServiceSyncTable<Job> jobTable;
public async Task InitializeAsync()
{
var store = new MobileServiceSQLiteStore("localdata.db");
store.DefineTable<Job> ();
await this.MobileService.SyncContext.InitializeAsync(store);
jobTable = this.MobileService.GetSyncTable<Job>();
jobTable = this.MobileService.GetSyncTable<Job>();
JObject newJob = new JObject ();
newJob.Add ("Id","job_123");
jobTable.InsertAsync (newJob);
this.MobileService.SyncContext.PushAsync();
var readResult = jobTable.ReadAsync ().Result.AsQueryable();
var resultList = from data in readResult
select data;
var resultCount = resultList.Count ();
}
So far - nothing gets synced up with my Sql Server db (which is on the recieving end of the Mobile Services), and the resultCount remain at 0
I'm sure I do something wrong here, just can't seem to nail what exactly.
-Eugene
You should use PullAsync instead of ReadAsync. Also, you need to await the call to all of your async method calls, such as InsertAsync, PushAsync, and PullAsync.
See this tutorial for a detailed example: http://azure.microsoft.com/en-us/documentation/articles/mobile-services-xamarin-ios-get-started-offline-data/

Predefined database in windows phone 8.1 app

Where predefined database (.db) should add and how to use it in windows phone 8.1 app?
I am not using Silverlight in my app.
I was trying to do something like this
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
CopyDatabase();
}
private void CopyDatabase()
{
IsolatedStorageFile ISF = IsolatedStorageFile.GetUserStoreForApplication();
String DBFile = "myDB.sqlite";
if (!ISF.FileExists(DBFile)) CopyFromContentToStorage(ISF, "Assets/myDB.sqlite", DBFile);
}
It showing that the namespace name IsolatedStorageFile could not be found.
I found those codes in a sample database app for Windows-phone-8.0 and I was trying to do the same thing in Windows-phone-8.1 (without Silverlight).
As I see you try to copy the database from package to IsolatedStorage and you are targeting WinRT. The sample code can llok like this:
private async Task<bool> CopyDatabase()
{
StorageFolder packageFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
StorageFile file = await packageFolder.GetFileAsync("Assets/myDB.sqlite");
await file.CopyAsync(localFolder);
return true;
}
I've written this code from the top of my head, but should work or help you to find the solution. The above is also possible by Uri schemes:
StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(#"ms-appx:///Assets/myDB.sqlite"));
More about Data and Files you will find at MSDN.

Resources