I have database and i want to import it in my project ,first i added a SQLITe component to my project and insert my DB to ASSETS folder.
All the examples that i have seen it's about how to create database in project, but i already have the database and i want to make some query to display it in my app.
I checked this tutorial:
Use a local database in Xamarin
But it does not work!
This my code:
void conndb ()
{
string dbName = "Chinook_Sqlite.sqlite";
string dbPath = Path.Combine (Android.OS.Environment.ExternalStorageDirectory.ToString (), dbName);
// Check if your DB has already been extracted.
if (!File.Exists(dbPath))
{
using (BinaryReader br = new BinaryReader(Assets.Open(dbName)))
{
using (BinaryWriter bw = new BinaryWriter(new FileStream(dbPath, FileMode.Create)))
{
byte[] buffer = new byte[2048];
int len = 0;
while ((len = br.Read(buffer, 0, buffer.Length)) > 0)
{
bw.Write (buffer, 0, len);
}
}
}
using (var conn = new SQLite.SQLiteConnection(dbPath))
{
var cmd = new SQLite.SQLiteCommand (conn);
cmd.CommandText = "select * from Album where AlbumId=1;";
var r = cmd.ExecuteQuery<Album> ();
Console.Write (r);
}
}
}
Any help?
You will need to upload your SQLite DB into your Android Device using the File Explorer. You will need to use Android Studio, I do not believe Xamarin Studio has the equivalent tool.
If you start Monitor from the Android Studio (green robot icon on the toolbar, to the left of the help icon) you can then can select File Explorer tab. You should be able to upload your DB File to the location you're calling in your Xamarin C# Code.
Related
I am struggling big time with generating QR barcodes as a byte[] or Stream (something that I can use on a XAML image source)
ZXING.NET
I've tried with Zxing.Net but I find the documentation is not great.
In fact, when installing in the xamarin forms class library I am able to compile, but as soon as I add some code to write barcodes I get a compilation error saying that
Can not resolve reference: `zxing`, referenced by `MyXamarinFormsClassLibrary`. Please add a NuGet package or assembly reference for `zxing`, or remove the reference to `Sasw.AforoPass`. 0
Something funky is going on with that library.
And I'm doing a simple example such as:
var options = new QrCodeEncodingOptions
{
DisableECI = true,
CharacterSet = "UTF-8",
Width = 250,
Height = 250
};
var writer = new BarcodeWriter<Image>();
writer.Format = BarcodeFormat.QR_CODE;
writer.Options = options;
var result = writer.Write("foo");
MyImage.Source = result.Source;
QRCoder
It's another nuget library. I've successfully used for dotnet core applications, but it does not seem to be compatible with Xamarin Forms (or Mono, or whatever). It says that the platform is not supported. Probably because it uses System.Drawing.Common?
ZXing.Net.Mobile.Forms
I've used this other library which underneath it uses ZXing.Net. What I don't like is that I don't know if there's any way to generate qr codes without relying on Xaml or the ZXingBarcodeImageView.
I managed to generate QR Codes that way as a workaround, but I hit another wall. See https://github.com/Redth/ZXing.Net.Mobile/issues/908 in which I describe the problems I have to embed the ZXingBarcodeImageView in a carousel inside a popup.
So basically I wanted to go back to the roots, and simply have a working example with the latest version of ZXing.Net (or an alternative, if it exists) that I am able to use in Xamarin Forms.
Most of the examples I find talk about BarcodeWriter but there is no such a class anymore. There is a generic one BarcodeWriter<TUnknownType>and a BarcodeWriterGeneric but as I said, I could not compile anything using Zxing.Net library and with through ZXing.Net.Mobile the images I generate are always empty.
Any help or "modern" code sample (ideally with an alternative) would be much appreciated
UPDATE 1
In other words, I'm looking to have in Xamarin Forms something similar to this code that I had using QrCoder library.
public class QrCodeService
: IQrCodeService
{
public Stream GetQrCode(Guid id, string mimeType = "image/jpeg")
{
if (mimeType is null)
{
throw new ArgumentNullException(nameof(mimeType));
}
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(id.ToString(), QRCodeGenerator.ECCLevel.Q);
var qrCode = new QRCode(qrCodeData);
var qrCodeImage = qrCode.GetGraphic(20);
var myImageCodecInfo = GetEncoderInfo(mimeType);
var myEncoder = Encoder.Quality;
var myEncoderParameters = new EncoderParameters(1);
var myEncoderParameter = new EncoderParameter(myEncoder, 50L);
myEncoderParameters.Param[0] = myEncoderParameter;
var stream = new MemoryStream();
qrCodeImage.Save(stream, myImageCodecInfo, myEncoderParameters);
stream.Position = 0;
return stream;
}
private static ImageCodecInfo GetEncoderInfo(string mimeType)
{
var encoders = ImageCodecInfo.GetImageEncoders();
foreach (var encoder in encoders)
{
if (encoder.MimeType == mimeType)
{
return encoder;
}
}
throw new KeyNotFoundException($"Encoder for {mimeType} not found");
}
}
The solution uses QrCoder library and it works fine for Xamarin Forms as follows.
private byte[] GetQrImageAsBytes()
{
var randomText = Guid.NewGuid().ToString();
var qrGenerator = new QRCodeGenerator();
var qrCodeData = qrGenerator.CreateQrCode(randomText, QRCodeGenerator.ECCLevel.L);
var qRCode = new PngByteQRCode(qrCodeData);
var qrCodeBytes = qRCode.GetGraphic(20);
return qrCodeBytes;
}
Here a working sample with this implementation
QrCoder library can do this, but instead of using as in the main page of the project:
QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode("The text which should be encoded.", QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData); // This point onwards is problematic
Bitmap qrCodeImage = qrCode.GetGraphic(20); // This will throw not supported exception
Switch the last 2 lines to:
var qrCode = new PngByteQRCode(qrCodeData);
byte[] imageByteArray = qrCode.GetGraphic(20);
You'll get byte array instead, but you can convert it into Stream or whatever you like afterwards.
My goal is to modify a .txt file in azure file storage using WindowsAzure.Storage API. I would like to know if there is any method to add some text in the file.
Is it easier to use the System.IO API?
I've already tried the cloudFileStream.Write() but it didn't work.
Thank you
The sample on https://github.com/Azure/azure-storage-net/blob/master/Test/WindowsRuntime/File/FileStreamTests.cs shows you how to do this.
public async Task FileOpenWriteTestAsync()
{
byte[] buffer = GetRandomBuffer(2 * 1024);
CloudFileShare share = GetRandomShareReference();
try
{
await share.CreateAsync();
CloudFile file = share.GetRootDirectoryReference().GetFileReference("file1");
using (CloudFileStream fileStream = await file.OpenWriteAsync(2048))
{
Stream fileStreamForWrite = fileStream;
await fileStreamForWrite.WriteAsync(buffer, 0, 2048);
await fileStreamForWrite.FlushAsync();
byte[] testBuffer = new byte[2048];
MemoryStream dstStream = new MemoryStream(testBuffer);
await file.DownloadRangeToStreamAsync(dstStream, null, null);
MemoryStream memStream = new MemoryStream(buffer);
TestHelper.AssertStreamsAreEqual(memStream, dstStream);
}
}
finally
{
share.DeleteIfExistsAsync().Wait();
}
}
If you want to add some text(append to the existing data) to the file on azure file storage, there is no direct method. You need to download it and then upload with the text you want to append.
string accountName = "xxx";
string key = "xxx";
var storageAccount = new CloudStorageAccount(new StorageCredentials(accountName, key), true);
var share = storageAccount.CreateCloudFileClient().GetShareReference("testfolder");
CloudFile file1 = share.GetRootDirectoryReference().GetFileReference("a.txt");
//if you want to append some text from local file
var stream1 = File.OpenRead("your file path in local, like d:\hello.txt");
string from_local_file = (new StreamReader(stream1)).ReadToEnd();
//if you just want to add some text from string, directly use the string
//string from_local_file ="the text I want to append to azure file";
//download the content of the azure file
string from_azure_file = file1.DownloadText();
//this does the trick like appending text to azure file, not overwrite
file1.UploadText(from_azure_file + from_local_file);
If you want to directly upload text to file stored on azure file storage, you should use one of the following methods: UploadText() / UploadFromFile() / UploadFromStream().
Note that this will overwrite the existing data in the azure file.
If you want to update the context of azure file, you can use WriteRange() method. But it has some limitations, if you're interesting about it, I can provide you some code.
i want to use use Sqllite datbase in my Android Game i am developing with Haxe - OpenFl but the app keep crashing when i am trying to query the database. If this is not possible or have any other ways to deal with data in Android kindly let me know as the json and shared objects are not going to work with in my scenario.
i posted this question in the OpenFl community too - but i think it is more related to Haxe then OpenFL.
OpenFl Community Post
What i am doing :
Making a database using DB Browser and saving it to the assets/data/db/data.db
then when app starts i am making a copy of it to the lime.system.System.applicationStorageDirectory
it creates the file in the applicationStorageDirectory
Then i try to connect to the newly created db file and it just connects but right after connecting to it, try to get the name of the db it is connected to
trace("Connected to database " +_conn.dbName ); and it is not showing anything in the trace except the text connected to database.
Ignoring the name i tried to query the Database and it just closes my app without any error or anything i get to know what goes wrong.
My Project.xml
<android target-sdk-version="26" install-location="preferExternal" if="android" />
<android permission="android.permission.WRITE_EXTERNAL_STORAGE"/>
<android permission="android.permission.WRITE_INTERNAL_STORAGE"/>
<haxelib name="openfl" />
<haxelib name="hxcpp" />
<assets path="assets/data/db" rename="db" />
DBClass
package;
import haxe.io.Bytes;
import lime.Assets;
import openfl.system.System;
import sys.FileSystem;
import sys.db.Connection;
import sys.db.Sqlite;
import sys.io.File;
#if android
// Make SQLite work on android by statically compiling the library
import hxcpp.StaticSqlite;
#end
/**
* ...
* #author Sim
*/
class DBManager
{
private var CLONE:String = "db/asset_database.db";
private var NEW:String = "new_db.db";
private var _conn:Connection = null;
public function new()
{
}
public function openDatabase():Void
{
trace("CREATING FILE");
trace("targetPath: " +lime.system.System.applicationStorageDirectory);
//trace("targetPath: " +lime.system.System.applicationDirectory); //Crashing the app
trace("targetPath: " +lime.system.System.documentsDirectory);
trace("targetPath: " +lime.system.System.desktopDirectory);
var targetPath: String = lime.system.System.applicationStorageDirectory+ NEW;
trace("targetPath " + targetPath);
trace("FileSystem.exists(targetPath) " + FileSystem.exists(targetPath));
//Debugging
/*var bytes:Bytes = Assets.getBytes(CLONE);
trace("bytes are here "+bytes);
var content:String = bytes.toString();
trace("content "+content);
File.saveContent(targetPath, content);
trace("Saved");*/
//uncomment when done with errors
/*if (FileSystem.exists(targetPath) == false)
{
var bytes:Bytes = Assets.getBytes(CLONE);
var content:String = bytes.toString();
File.saveContent(targetPath, content);
}*/
var bytes:Bytes = Assets.getBytes(CLONE);
var content:String = bytes.toString();
File.saveContent(targetPath, content);
trace("Saved");
try
{
_conn = Sqlite.open(targetPath+NEW);
}
catch (e:Dynamic)
{
trace("Connection failed with error: "+e);
}
if (_conn != null)
{
trace("Connected to database " +_conn.dbName );
//not getting any database name trying to query
// and KaBoom app gone :D XD
var result = _conn.request("SELECT * FROM TEST");
trace("Query Result "+result.results());
//if i comment then it will go and close the connection too
//without breaking anything O_O
_conn.close();
}
}
}
I took a nap and got the fix in my dreams: :D
The problem is here
_conn = Sqlite.open(targetPath+NEW);
Fix:
_conn = Sqlite.open(targetPath);
Because database name is already in the path :P
var targetPath: String = lime.system.System.applicationStorageDirectory+ NEW;
That’s why always sleep for 8 hours otherwise will end up like me
I'm trying to drop in sqlite support for saving the score and some flags. I need to open the db if it exists, then init game values based on db. If the db does not exist, I need to create/init it. The code below compiles but crashes for unknown reason.
package mygame;
<snip imports>
import sys.db.Types;
class ScoreDB extends sys.db.Object {
public var id : SId;
public var dbscore1 : SInt;
public var dbsound : SInt;
public var dbscore2 : SInt;
}
class mygame extends Sprite {
<snip var defines>
public function new () {
// start sqlite code
sys.db.Manager.initialize();
// db does exist
// then read values
// currentScore = score1.dbscore1;
// doSound = score1.dbsound;
// doScore = score1.dbscore2;
// db does not exist:
var cnx = sys.db.Sqlite.open("mybase.db");
sys.db.Manager.cnx = cnx;
sys.db.TableCreate.create(ScoreDB.manager);
var score1 = new ScoreDB();
score1.id = 0;
score1.dbscore1 = 0;
score1.dbsound = 0;
score1.dbscore2 = 0;
score1.insert();
currentScore = 0;
doSound = 0;
doScore = 0;
cnx.close();
// end sqlite code
super ();
initialize ();
construct ();
newGame ();
}
I actually just solved the same issue.
The problem is that the app is essentially a .zip file and cannot be edited. You need to create (and later access) the DB in the app storage directory.
To access the directory use following code:
private static var localStoragePath:String = openfl.utils.SystemPath.applicationStorageDirectory;
There is a known bug that the IDE's don't show the SystemPath class, but don't mind it, it will compile without problem.
Later, with your common tools you can read and write the directory, create new folders etc.
Here's a quick test, to make sure it works and doesn't crash:
// creating a test folder
sys.FileSystem.createDirectory(openfl.utils.SystemPath.applicationStorageDirectory + "/testFolder");
var form:TextFormat = new TextFormat(null, 22, 0xFFFFFF);
// getting contents of the storage dir
var arr = sys.FileSystem.readDirectory(openfl.utils.SystemPath.applicationStorageDirectory);
var tf:TextField = new TextField();
tf.defaultTextFormat = form;
tf.width = Lib.current.stage.stageWidth;
tf.height = Lib.current.stage.stageHeight;
tf.multiline = true;
tf.wordWrap = true;
tf.text = arr.toString();
addChild(tf);
as you'll see, the newly created folder is there. You can delete the line that creates the folder and you'll see it's safe.
Oh, an don't forget to add Android permissions in the XML file:
<android permission="android.permission.WRITE_EXTERNAL_STORAGE"/>
As far as I know there is no sqlite definitions in openfl. And the ones you use are just normal cpp target definition. I suppose the problem is they don't work on android. Even more: I'm quite sure the api definitions are ok, but it tries to load dll with a wrong name, which probably kills your app without even letting out an error. Try to look into implementation(it is short and easy to understand) and change the dll name.
Jeff wrote about getting a file version/datestamp a while back. Visual studio doesn't increment builds unless you close/reopen the solution, so grabbing the timestamp seems to be the best way to verify what build you are using.
I ported the solution to C#
// from http://www.codinghorror.com/blog/archives/000264.html
protected DateTime getLinkerTimeStamp(string filepath){
const int peHeaderOffset = 60;
const int linkerTimestampOffset = 8;
byte[] b = new byte[2048];
Stream s = null;
try {
s = new FileStream(filepath, FileMode.Open, FileAccess.Read);
s.Read(b, 0, 2048);
}
finally{
if (s != null){
s.Close();
}
}
int i = BitConverter.ToInt32(b, peHeaderOffset);
int secondsSince1970 = BitConverter.ToInt32(b, i + linkerTimestampOffset);
DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0);
dt = dt.AddSeconds(secondsSince1970);
dt = dt.AddHours(TimeZone.CurrentTimeZone.GetUtcOffset(dt).Hours);
return dt;
}
protected DateTime getBuildTime()
{
System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
return getLinkerTimeStamp(assembly.Location);
}
Which seems to work. Is there a better / more official way to tell when a site was deployed?
I think your easiest route is to have a timestamp in your web.config.
There are really two ways you can update this in your web.config. The first is to use an automated build tool such as NAnt. It gives you the option of modifying the web.config like you would want. This is the method I use.
Another option available to you if you don't use an automated build tool is to add code in your pre-build event in Visual Studio to update the web.config for you. Here is an article on Codeplex which should get you started.
http://www.codeproject.com/KB/dotnet/configmanager_net.aspx