I am following this guide to add SQLite into my Xamarin.Forms Shared Asset project. It's not a PCL. I am using XAML with Code Behind.
I seem to have all the code in all the right places. I have an SQLite.cs which contains all of my DB calls I want to make and also defines the database.
I have an Interface defined inside a class I know works and is accessible as other functions in it are being consumed.
I then have a class in each platform project (I have show below the droid example) which uses the interface to get the local file path.
And finally in my Shared Asset project I define and (should) instantiate (I think) my database.
So with all that in place, In one of my ViewModels I try and execute a database call. However the inner exception reveals that I'm getting an Object Reference error. Basically my "database" object is null when it tries to execute database.MyMethod().
I can't work out why its not getting instantiated. Any ideas?
The line it executes is
var dbtimings = TechsportiseData.GetTimingsAsync().Result.ToList();
That method is...
public static Task<List<Timing>> GetTimingsAsync()
{
return database.Table<Timing>().ToListAsync();
}
and it trips over because database is null.
SQLite.cs (Shared Asset Project)
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
using static TechsportiseApp.Helpers.GlobalFunctions;
using TechsportiseApp.Models;
using System.Threading.Tasks;
using SQLite;
namespace TechsportiseApp.Data
{
public class TechsportiseData
{
readonly SQLiteAsyncConnection database;
public TechsportiseData(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Scan>().Wait();
database.CreateTableAsync<Timing>().Wait();
}
public static Task<List<Timing>> GetTimingsAsync()
{
return database.Table<Timing>().ToListAsync();
}
public static Task<List<Timing>> GetTimingsNotUploadedAsync()
{
return database.QueryAsync<Timing>("SELECT * FROM [Timing] WHERE [Uploaded] = 0");
}
public static Task<Timing> GetTimingAsync(int id)
{
return database.Table<Timing>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
public static Task<int> SaveTimingAsync(Timing timing)
{
if (timing.Id != 0)
{
return database.UpdateAsync(timing);
}
else
{
return database.InsertAsync(timing);
}
}
public static Task<int> DeleteTimingAsync(Timing timing)
{
return database.DeleteAsync(timing);
}
public static Task DeleteAllTimingsAsync()
{
database.DropTableAsync<Timing>().Wait();
return database.CreateTableAsync<Timing>();
}
public static Task<List<Scan>> GetScansAsync()
{
return database.Table<Scan>().ToListAsync();
}
public static Task<List<Scan>> GetScansNotUploadedAsync()
{
return database.QueryAsync<Scan>("SELECT * FROM [Scan] WHERE [Uploaded] = 0");
}
public static Task<Scan> GetScanAsync(int id)
{
return database.Table<Scan>().Where(i => i.Id == id).FirstOrDefaultAsync();
}
public static Task<int> SaveScanAsync(Scan scan)
{
if (scan.Id != 0)
{
return database.UpdateAsync(scan);
}
else
{
return database.InsertAsync(scan);
}
}
public static Task<int> DeleteScanAsync(Scan scan)
{
return database.DeleteAsync(scan);
}
public static Task DeleteAllScansAsync()
{
database.DropTableAsync<Scan>().Wait();
return database.CreateTableAsync<Scan>();
}
public static Task<RaceClock> GetRaceClockAsync()
{
return database.Table<RaceClock>().FirstOrDefaultAsync();
}
public static Task<int> SaveRaceClockAsync(RaceClock clock)
{
return database.InsertAsync(clock);
}
public static Task DeleteRaceClockAsync()
{
database.DropTableAsync<RaceClock>().Wait();
return database.CreateTableAsync<RaceClock>();
}
}
}
App.xaml.cs
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using System.Collections.Generic;
using TechsportiseApp.API;
using TechsportiseApp.Views;
using TechsportiseApp.ViewModels;
using TechsportiseApp.Models;
using TechsportiseApp.Helpers;
using TechsportiseApp.Data;
using static TechsportiseApp.Helpers.GlobalFunctions;
//[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace TechsportiseApp
{
public partial class App : Application
{
static TechsportiseData database;
public App()
{
InitializeComponent();
Application.Current.Properties["APIServer"] = "https://www.techsportise.com/";
//Application.Current.Properties["APIServer"] = "http://localhost:52693/";
if (Application.Current.Properties.ContainsKey("ShowHelpOnStartup") == false)
{
Application.Current.Properties["ShowHelpOnStartup"] = true;
}
if (Application.Current.Properties.ContainsKey("ShowCompletedRaces") == false)
{
Application.Current.Properties["ShowCompletedRaces"] = false;
}
//MainPage = new NavigationPage(new ResultsProcess());
//MainPage = new NavigationPage(new Scanning());
//If the token is present and they are remembered
if ((Application.Current.Properties.ContainsKey("Token")) && (Application.Current.Properties.ContainsKey("IsRemembered")))
{
//And is blank/null
if (((string)Application.Current.Properties["Token"] == "") || ((GlobalFunctions.PropertyToBool(Application.Current.Properties["IsRemembered"].ToString()) != true)))
{
//They need to login
MainPage = new NavigationPage(new Login());
}
//Otherwise they can go straight to their page
else
{
if (GlobalFunctions.PropertyToBool(Application.Current.Properties["ShowHelpOnStartup"].ToString()) == true)
{
MainPage = new StartupHelp(true);
}
else
{
MainPage = new MainMenuMasterDetail();
}
}
}
else
{
MainPage = new NavigationPage(new Login());
}
}
public static TechsportiseData Database
{
get
{
if (database == null)
{
database = new TechsportiseData(DependencyService.Get<IFileHelper>().GetLocalFilePath("Techsportise.db3"));
}
return database;
}
}
protected override void OnStart()
{
// Handle when your app starts
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
Interface (Shared Assets project)
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using Xamarin.Forms;
namespace TechsportiseApp.Helpers
{
public class GlobalFunctions
{
public GlobalFunctions()
{
}
public interface IFileHelper
{
string GetLocalFilePath(string filename);
}
public static bool CheckForInternetConnection()
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
request.Timeout = 5000;
request.Credentials = CredentialCache.DefaultNetworkCredentials;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
return true;
else
//return false;
return true;
}
catch
{
//return false;
return true;
}
}
public static bool HasPremium()
{
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadToken(Application.Current.Properties["Token"].ToString()) as JwtSecurityToken;
var premium = token.Claims.FirstOrDefault(claim => claim.Type == "premium").Value.ToString();
var premiumbool = PropertyToBool(premium);
return premiumbool;
}
}
}
Platform Class (Droid in this example)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using TechsportiseApp.Droid;
using static TechsportiseApp.Helpers.GlobalFunctions;
using System.IO;
[assembly: Dependency(typeof(FileHelper))]
namespace TechsportiseApp.Droid
{
public class FileHelper : IFileHelper
{
public string GetLocalFilePath(string filename)
{
string path = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
return Path.Combine(path, filename);
}
}
}