so i have already made one app that was a test app and it worked just fine using sqlite-net-pcl and i an now making an actual app and i am getting this weird error and i cant figure out why. i found the exact same question already asked on here but it didnt provide any real answer and it was over a year ago.
System.Exception: Something went wrong in the build configuration. This is the bait assembly, which is for referencing by portable libraries, and should never end up part of the app. Reference the appropriate platform assembly instead.
public SQLite.SQLiteConnection GetConnection()
{
var sqliteFilename = "TestDB.db3";
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal); // Documents folder
var path = Path.Combine(documentsPath, sqliteFilename);
// Create the connection
var conn = new SQLite.SQLiteConnection(path);//HERE IS WHERE IT THROWS THE EXCEPTION
// Return the database connection
return conn;
}
the app works for every other platform i have tried except android and my test app that worked just fine is using the exact same references and same class as well i just cant figure it out. i have tried referencing the sqlite-net-pcl and made a new class still doesnt work. any help would be greatly appreciated
thank you very much
Here is the one I am using
https://github.com/oysteinkrog/SQLite.Net-PCL
Check you referenced SQLite.Net.Platform.XamarinAndroid in your Android project.
Here is the code which is working fine for me (I also included SQLite.Net.Async-PCL)
public SQLiteAsyncConnection GetConnection()
{
// database name
const string SQLITE_FILENAME = "MyDB.db3";
// Get app folder
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
string path = Path.Combine(documentsPath, SQLITE_FILENAME);
var plat = new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid();
var sqliteConnection = new SQLiteConnectionWithLock(plat, new SQLiteConnectionString(path, true)){BusyTimeout = TimeSpan.FromSeconds(5)};
var conn = new SQLiteAsyncConnection(() => sqliteConnection,
TaskScheduler.FromCurrentSynchronizationContext());
// Return the database connection
return conn;
}
Guess this should work:
public SQLiteConnection GetConnection()
{
// database name
const string SQLITE_FILENAME = "MySIT.db3";
// Get app folder
string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
var plat = new SQLite.Net.Platform.XamarinAndroid.SQLitePlatformAndroid(); //important!
string path = Path.Combine(documentsPath, SQLITE_FILENAME);
var conn = new SQLiteConnection(plat, path);
// Return the database connection
return conn;
}
Related
I am using Dotmim.sync framework. I am trying to sync an mssql database with my xamarin android app's sqlite database. So I implemented the web proxy to reach the database from the android app.
The proxy starts fine, but then when I call the sync from the android app the Post method gives a null reference error, but I cannot find what is null.
In the ASP.NET Core web app's Startup file:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
// [Required]: To be able to handle multiple sessions
services.AddMemoryCache();
// [Required]: Get a connection string to your server data source
var connectionString = #"[my connection string]";
// [Required]: Tables list involved in the sync process
var tables = new string[] { "dbo.Album", "dbo.Artist", "dbo.Customer", "dbo.Invoice", "dbo.InvoiceItem", "dbo.Track" };
// [Required]: Add a SqlSyncProvider acting as the server hub.
services.AddSyncServer<SqlSyncChangeTrackingProvider>(connectionString, tables);
}
The SyncController:
[ApiController]
[Route("api/[controller]")]
public class SyncController : ControllerBase
{
private WebServerManager manager;
public SyncController(WebServerManager man) => this.manager = man;
[HttpPost]
public async Task Post()
{
await manager.HandleRequestAsync(this.HttpContext);
} //----> the Null error comes
[HttpGet]
public async Task Get() => await manager.HandleRequestAsync(this.HttpContext);
}
In the android app the sync function that is called:
public async Task SyncDatabase(string connString, Context context)
{
var handler = HttpClientHandlerService.GetInsecureHandler();
HttpClient httpClient = new HttpClient(handler);
httpClient.DefaultRequestHeaders.Host = $"localhost:44372";
var serverOrchestrator = new WebClientOrchestrator("https://10.0.2.2:44372/api/sync", client: httpClient);
// Second provider is using plain sqlite provider
var clientProvider = new SqliteSyncProvider(connString);
var agent = new SyncAgent(clientProvider, serverOrchestrator);
try
{
var result = await agent.SynchronizeAsync(); //---> error comes when this line is called
var output = result.ToString();
output = output.Replace("\n", " ").Replace("\t", " ").Replace("\r", " ");
Toast.MakeText(context, output, ToastLength.Long).Show();
}
catch (Exception e)
{
Toast.MakeText(context, e.Message, ToastLength.Long).Show();
}
}
Let me know what further information should I supply to solve this.
EDIT:
Calling from postman it gives this error: {"tn":"HttpHeaderMissingExceptiopn","m":"Header dotmim-sync-scope-name is missing."}
EDIT2:
Server orchestrator on the client side:
On the server side:
The details of the exception:
SOLUTION:
I tried the sync with a different database and tables, and that worked, so it was clear that dotmim has some problem with the tables I was using. So after lot of thinking I tried with a different schema name instead of dbo, since the other database that worked had something else. And it turns out the sync has some problem if the schema name is dbo, something gets mixed probably when it tries to create its own new tables. So use something different from dbo for schema.
Looking at this issue xamarin/Essentials#1322, how do I download a file on both Android ( versions 6-10, Api 23-29 ) and iOS ( version 13.1+ ) that is publicly available (share-able to other apps, such as Microsoft Word). I don't need to give write access to the other apps, just read-only is ok if it must be restricted.
I get the following exception:
[Bug] Android.OS.FileUriExposedException: file:///data/user/0/{AppBundleName}/cache/file.doc exposed beyond app through Intent.getData()
With the following code.
public static string GetCacheDataPath( string fileName ) => Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, fileName);
public static FileInfo SaveFile( string filename, Uri link )
{
using var client = new WebClient();
string path = GetCacheDataPath(filename);
DebugTools.PrintMessage(path);
client.DownloadFile(link, path);
return new FileInfo(path);
}
public async Task Test(Uri link)
{
LocalFile path = await SaveFile("file.doc", link).ConfigureAwait(true);
var url = new Uri($"ms-word://{path.FullName}", UriKind.Absolute);
await Xamarin.Essentials.Launcher.OpenAsync(url).ConfigureAwait(true);
}
With this answer, I created a FileService interface and it works with local private files but I am unable to share the files. Starting with Android Q (10 / Api 29), the following is deprecated.
string path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads).AbsolutePath; // deprecated
I get the following exception:
System.UnauthorizedAccessException: Access to the path '/storage/emulated/0/Download/file.doc' is denied. ---> System.IO.IOException: Permission denied
I haven't found any way yet to get a public path for Android 10 with Xamarin.Forms. I've looked at the Android Docs for Content providers but it's in Java, and I can't get it working in C# yet.
Any help would be greatly appreciated.
I did find a Solution
Found a fix
For Android
public Task<System.IO.FileInfo> DownloadFile( Uri link, string fileName )
{
if ( link is null )
throw new ArgumentNullException(nameof(link));
using System.Net.WebClient client = new System.Net.WebClient();
// MainActivity is the class that loads the application.
// MainActivity.Instance is a property that you set "Instance = this;" inside of OnCreate.
Java.IO.File root = MainActivity.Instance.GetExternalFilesDir(MediaStore.Downloads.ContentType);
string path = Path.Combine(root.AbsolutePath, fileName);
client.DownloadFile(link, path);
return Task.FromResult(new System.IO.FileInfo(path));
}
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
protected override void OnCreate(Bundle savedInstanceState)
{
...
Instance = this;
...
}
...
}
For iOS
public Task<System.IO.FileInfo> DownloadFile( Uri link, string fileName )
{
if ( link is null )
throw new ArgumentNullException(nameof(link));
using System.Net.WebClient client = new System.Net.WebClient();
string path = Path.Combine(Xamarin.Essentials.FileSystem.CacheDirectory, fileName)
client.DownloadFile(link, path);
return Task.FromResult(new System.IO.FileInfo(path));
}
public async Task Share()
{
// back in shared project, choose a file name and pass the link.
System.IO.FileInfo info = await DependencyService.Get<IDownload>().DownloadFile(new Uri("<enter site>", "file.doc").ConfigureAwait(true);
ShareFile shareFile = new ShareFile(info.FullName, "doc"); // enter the file type / extension.
var request = new ShareFileRequest("Choose the App to open the file", shareFile);
await Xamarin.Essentials.Share.RequestAsync(request).ConfigureAwait(true);
}
Note that for iOS, due to Apple's infinite wisdom... I cannot share the file directly with another app as I can on Android. Sandboxing is good for security but in this case, how they implemented it, it limits options. Both Applications must be pre-registered / pre-allocated in an "App Group" to share files directly. See this Article and the Apple Docs for more information.
we have an app under xamarin android build with visual studio 2017.
this app works since three years without any problems.
since two weeks and I don't know why actually some device can't sync with our back end.
It's really strange because nothing has change in this part .
this error does not appear on all devices but on one or two from time to time
we use the dll httpClient for to sync the datas with our backend.
If i put a break point inside the postAsync I have an exception with this -> Cannot access a disposed object. Object name: 'System.Net.Sockets.NetworkStream
Any one has an idea about how to solve this ? also what does it meam ?
Here is it the code of the postAsync method :
thanks for our time and comment guys
public override HttpResult ExecutePost(Uri target, string body)
{
var client = new HttpClient();
client.MaxResponseContentBufferSize = MaxHttpResponseBufferSize;
try
{
var requestContent = new StringContent(body, RequestContentEncoding, RequestContentType);
var response = client.PostAsync(target, requestContent).Result;
if (response.IsSuccessStatusCode)
{
var content = response.Content.ReadAsStringAsync().Result;
return new HttpResult(content, null, null);
}
return new HttpResult(null, "Response is empty", response.StatusCode.ToString());
}
catch (Exception e)
{
return new HttpResult(null, "Problem with the HttpPost", e.Message);
}
}
I experienced the same issue. Have been battling for 6 hours on this issue.
If you read the error, I was getting (Failed to connect to localhost/127.0.0.1:7113). If you put localhost in your browser or swagger tool it will work but if you put https://127.0.0.1:7113/api/weatherforecast in your browser it will not work. It will give you a certificate problem.
So I think you have to resolve 127.0.0.1 to localhost with https certificate on your local dev machine.
I'm building a MAUI app with Visual Studio 2022 Preview.
So I solved this issue by deploying my API to AZURE.
Then update to the azure url for example:
string apiUrl = "https://weatherforecast.azurewebsites.net/api/weatherforecast";
and then it worked brilliantly. Like super brilliantly.
Here is my code:
public void LoginAsync()
{
HttpClient client = new HttpClient();
string apiUrl = "https://weatherforecast.azurewebsites.net/api/weatherforecast";
UserCredentials.EmailAddress = LoginUIEntity.EmailAddress;
UserCredentials.Password = LoginUIEntity.Password;
string serialized = JsonConvert.SerializeObject(UserCredentials);
var inputMessage = new HttpRequestMessage
{
Content = new StringContent(serialized, Encoding.UTF8, "application/json")
};
inputMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
try
{
var message = client.PostAsync(apiUrl, inputMessage.Content).Result;
if (message.IsSuccessStatusCode)
{
var apiResponse = message.Content.ReadAsStringAsync();
UserCredentials = JsonConvert.DeserializeObject<UserCredentials>(apiResponse.Result);
if (UserCredentials.IsValid)
{
UserCredentials.IsLoggedIn = true;
}
else
{
ErrorMessage = "Invalid credentials supplied.";
}
}
}
catch (Exception ex)
{
ErrorMessage = "An error has occurred. Please contact support if the error persists.";
}
}
}
thanks for the link your provide.
I've try up the buffer on the postasync / try to sync in wifi OR 3G / delete special character in json / ...
but nothing work
we have move the prod database to the test and try to sync the data to the test database with postman. with postman the result was ENTITY TOO LARGE !
Json is size > 1.2 mega and the default value inside IIS is set to 1 mega
Here is it the problem ...
thanks problem solve
I´m trying to do an array to storage data with local storage. it works pretty well on google emulator. but isn´t working on my android device.
I found this code on the internet to put array in localstorage, and it works.
Storage.prototype.setArray = function (key, obj) {
return this.setItem(key, JSON.stringify(obj))
}
Storage.prototype.getArray = function (key) {
return JSON.parse(this.getItem(key))
}
then i create an function to get and set the data there.
function teste() {
var bd = [];
bd = window.localStorage.getArray("banco");
var nome = $('#name2').val();
alert(nome);
var area = $('#textarea2').val();
alert(area);
var meuservico = new servico(nome, area);
bd.push(meuservico);
alert(bd[0].nome);
window.localStorage.setArray("banco", bd);
}
and I also made an object called service.
function servico(nome,area){
this.nome = nome;
this.area = area;
}
this code work! but only on browser . how do I make it work on android? I don´t really wanna work with strings in localstorage. please help me!.
I tried with this too and didn´t work on device either.
localStorage.setItem('session', JSON.stringify(session));
var restoredSession = JSON.parse(localStorage.getItem('session'));
This is my first time really getting my teeth into Air for Android so please forgive me if this issue has been covered already. If it has then I've been unable to find it.
So I have an application that loads and displays xml data.
In the app I've got code to check if wiFi or equivalent is available and if so then pull live xml file and if not then pull the local xml file that was packaged with the application.
The app works fine if I am pulling in the xml from the live url but not if pulling from local.
After doing some research I discovered that when pulling in local file then Air for Android works slightly differently. So I need to resolve the application directory.
I did this and still no joy.
After a bit more research I read some post's that said I should use fileStream()
Tried this and still nada :(
All the time whilst testing in Flash IDE it works as intended.
If I had any more hair left I would be pulling it out right now!
The local xml file is set in the "includes"
Sample code below I am using for testing
var subURL:String = "xml_feeds/myxmlfile.xml"
var fileStream:FileStream = new FileStream();
var file:File = File.applicationDirectory.resolvePath(subURL);
fileStream.addEventListener(Event.COMPLETE, processXMLData);
fileStream.openAsync(file, FileMode.READ);
MovieClip(parent).txStates.text = file.url+" - TRYING"
var prefsXML:XML = new XML()
function processXMLData(event:Event):void{
MovieClip(parent).txStates.text = file.url+" - OPEN"
prefsXML = XML(fileStream.readUTFBytes(fileStream.bytesAvailable));
var tempArr:Array = new Array();
var reportCount:Number = prefsXML.row.column.length()
for (var i = 0; i < reportCount; i++) {
var rName:String = prefsXML.row.column[i].#name.toString();
var rValue:String = prefsXML.row.column[i].toString();
var rTitle:String = prefsXML.row.column[i].#name.toString()
tempArr.push([rName, rValue, rTitle]);
}
showData()
fileStream.close();
}
Is there anything I've missed?
UPDATE: 21/08/12
No idea what is going on with this. Here is the code i now have to use in order to load in the local xml file. Seems rather long winded
function listing():void{
var folders:Array = new Array();
folders = File.applicationDirectory.getDirectoryListing();
for(var i:Number =0;i<folders.length;i++){
if(folders[i].isDirectory){
if(folders[i].name=="xml_feeds"){
var files:Array = new Array();
files = folders[i].getDirectoryListing();
for(var j:Number=0;j<files.length;j++){
if(files[j].name=="CTSection2.xml"){
fileStream.openAsync(files[j], FileMode.READ);
fileStream.addEventListener(Event.COMPLETE, processXMLData);
fileStream.addEventListener(IOErrorEvent.IO_ERROR, localXMLFailLoad);
}
}
}
}
}
}