"Permission to path denied" in Xamarin when trying to save file to user device, no matter what - xamarin

When I try to do a "File.WriteBytes" or something similar (to save a byte file to user device) an error of permission to access the path always blows up. I tried everything, permissions on Manifest, using the plugin Permissions, changing the path to save it...funny how with Download Manager I can download a file in the same folder without errors. Any idea what's happening?
private async void OnDownloadStart(object sender, Android.Webkit.DownloadEventArgs e)
{
try
{
var url = e.Url;
var url_formatted = url.Split(",");
var base64EncodedBytes = System.Convert.FromBase64String(url_formatted[1]);
var decoded = System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
var directory = Android.App.Application.Context.GetExternalFilesDir("").AbsolutePath;
FileStream fs = new FileStream(directory,
FileMode.Create,
FileAccess.ReadWrite,
FileShare.ReadWrite,
4096,
FileOptions.Asynchronous);
fs.Write(base64EncodedBytes, 0, base64EncodedBytes.Length);
fs.Close();
}
catch (System.Exception ex)
{
var message = ex.Message;
throw;
}
}

Related

Unable to Export Sqlite database from SpecialFolder.ApplicationData to SD Card Xamarin Forms

I am currently developing an app that uses the sqlite-net database. I am trying to copy/export the database to my SD Card. When I run the code I get a System.NullRefrenceException: 'Object reference not set to an instance of an object.'
I have tried several solutions but I always get the same exception. The issues occurs at the System.IO.File.WriteAllBytes(fileCopyName, bytes); Please help.
private void CopyDBButton_Clicked(object sender, EventArgs e)
{
var basePath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var finalPath = Path.Combine(basePath, "Mydatabase");
CopyDatabase(finalPath);
}
public static void CopyDatabase(string databasePath)
{
var bytes = System.IO.File.ReadAllBytes(databasePath);
var fileCopyName = string.Format("/sdcard/Database_{0:dd-MM-yyyy_HH-mm-ss-tt}.db", System.DateTime.Now);
System.IO.File.WriteAllBytes(fileCopyName, bytes);
}
Did you add the two permissions listed below in your manifest file?
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
If you have confirmed that the above permissions are correctly being added, please try the code to export data from the app storage onto your SD Card:
private void Button_Clicked(object sender, EventArgs e)
{
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "TodoSQLite.db3");
var bytes = File.ReadAllBytes(path);
var fileCopyName = string.Format("/sdcard/Database_{0:dd-MM-yyyy_HH-mm-ss-tt}.db", DateTime.Now);
File.WriteAllBytes(fileCopyName, bytes);
}
The issue was the path address. I fixed it by checking for the directory first to see if it exists, then I copy the database to the directory in a new/existing file. The issue I have now is that the file saves to phone but not the SD card, but I am just happy that the backup file is finally saving.
Below is the code is used to fix the issue:
private void CopyDBButton_Clicked(object sender, EventArgs e)
{
//Used to find the database in the special folder
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Mydatabase");
//Used to locate the SD Card path
string path1 = Path.Combine("/sdcard/", Android.OS.Environment.DirectoryDownloads);
//Used to save the Database to a byte array
var bytes = File.ReadAllBytes(path);
//Used to check if the directory exists
if (!Directory.Exists(path1))
{
//Directory.CreateDirectory(filePathDir);
Console.WriteLine("Doesnt Exist");
}
else
{
Console.WriteLine("Does Exist");
//Used to create the name of the new Database backup file
var fileCopyName = string.Format(path1 + "/Database_{0:dd-MM-yyyy_HH-mm-ss-tt}.db", DateTime.Now);
//Write to the new database backup file
File.WriteAllBytes(fileCopyName, bytes);
}
}

Silverlight app freezes on Mac when file saved

Pretty simple code to launch SaveFileDialog and then save data.
Opens prompt, I can select where I save, it saves file and then whole tab/app freezes. Obviously works fine on Windows/IE. Any suggestions?
private void SavePDFFile()
{
var saveFileDialog = new SaveFileDialog
{
DefaultExt = "pdf",
Filter = string.Format("Document(.{0})|*.{0}", "pdf"),
FilterIndex = 1,
DefaultFileName = DateTime.Now.ToString("HHmmMMddyyyy")
};
var saveClicked = saveFileDialog.ShowDialog();
if (!saveClicked.HasValue || !saveClicked.Value) return;
var fileStream = saveFileDialog.OpenFile();
try
{
this.IsBusy = true;
fileStream.Write(this.PDFData, 0, this.PDFData.Length);
fileStream.Close();
}
catch (Exception ex)
{
this.DisplayErrorMessage("Error saving PDF file", ex);
}
finally
{
this.IsBusy = false;
}
}
Answering my own question. This is nothing to do with code itself. It is security issue. In order to allow this code to execute on Mac (and it seems new versions of IE as well) you need to give it more permissions.
On IE you need to add website to list of Trusted sites.
On Mac - you need to set Silverlight to run in "Unsafe" mode. This is in Preferences/Security/Silverlight and need to select website, hold "Option" key and then open dropdown to see that option. Took a while to find it..
#katit I also faced this issue while working on a Silverlight OOB application.. my app was working fine in Windows but in Mac it got freezed and I have to force quit to use it again.
I was actually reading a PDF (stored in field type - 'varbinary') from server and storing it to user's local machine.
The solution worked for me is to download file chunks in parts (I used buffer size - 1 MB).
Not sure what file size you are using when your application gets freeze.. but I think, writing 'PDFData' to filestream in small parts may help you.
Also, add filestream.Flush(); (see highlighted in below code) in your code and see if this helps:
private void SavePDFFile()
{
var saveFileDialog = new SaveFileDialog
{
DefaultExt = "pdf",
Filter = string.Format("Document(.{0})|*.{0}", "pdf"),
FilterIndex = 1,
DefaultFileName = DateTime.Now.ToString("HHmmMMddyyyy")
};
var saveClicked = saveFileDialog.ShowDialog();
if (!saveClicked.HasValue || !saveClicked.Value) return;
var fileStream = saveFileDialog.OpenFile();
try
{
this.IsBusy = true;
fileStream.Write(this.PDFData, 0, this.PDFData.Length);
**filestream.Flush();**
fileStream.Close();
}
catch (Exception ex)
{
this.DisplayErrorMessage("Error saving PDF file", ex);
}
finally
{
this.IsBusy = false;
}
}

How can i open an image in it's full size in UWP

I am working on a chat app:
If the user taps on an image, it will show in full size. The following method is called:
Handle_Tapped():
void Handle_Tapped(object sender, System.EventArgs e)
{
try
{
Image image = sender as Image;
string filePath = String.Empty;
filePath = image.Source as FileImageSource;
Eva3Toolkit.CommonUtils.openImage(filePath);
}
catch (Exception ex)
{
throw ex;
}
}
Which calls (depending on the OS):
openImage() in Android:
public void openImage(string filePath)
{
Intent sendIntent = new Intent(Intent.ActionView);
sendIntent.SetDataAndType(Android.Net.Uri.Parse("file:" + filePath), "image/*");
Forms.Context.StartActivity(Intent.CreateChooser(sendIntent, "Bild öffnen..."));
}
openImage() in iOS:
public void openImage(string filePath)
{
var firstController = ((UIApplicationDelegate)(UIApplication.SharedApplication.Delegate)).Window.RootViewController.ChildViewControllers[0].ChildViewControllers[1].ChildViewControllers[0];
var navcontroller = firstController as UINavigationController;
var docIC = UIDocumentInteractionController.FromUrl(new NSUrl(filePath, true));
docIC.Delegate = new DocInteractionC(navcontroller);
docIC.PresentPreview(true);
}
Now I want to create a method openImage() in UWP, but I don't know know. I know that I will most likely have to work with the image as a StorageFile instead of the path because only a StorageFile grants me permission to open the image.
Is there a way to open the image in full size in UWP? I highly prefer to not create a new view for this.
A Launcher can open a file with the program that is assigned to the file:
public async void openImageAsync(string filePath)
{
StorageFile storageFile = await StorageFile.GetFileFromPathAsync(filePath);
await Launcher.LaunchFileAsync(storageFile);
}
For my situation it's working that I use filePath because the files are in a local folder.
The output looks like this:

App Engine Blobstore/ImageService - Served image has not the original size

I managed to create the functionality to upload an image with the "gwtuploaded" to the app engine and store the image as an blob. My problem now is: The url that I get from imagesService.getServingUrl(suo) links to an image which is smaller than the image i uploaded. If i check the image in the blob viewer in the app engine console, it seems to have the correct size.
Why do I get a resized version of my image with the following code. Can I somehow retrieve the url to the full sized image?
My code looks like this:
public class MyUploadAction extends AppEngineUploadAction{
#Override
public String executeAction(HttpServletRequest request, List<FileItem> sessionFiles) throws UploadActionException {
String imageUrls = "";
// Image service is needed to get url from blob
ImagesService imagesService = ImagesServiceFactory.getImagesService();
// Get a file service -> write the blob
FileService fileService = FileServiceFactory.getFileService();
// Iterate over the files and upload each one
for(FileItem myFile : sessionFiles){
InputStream imgStream = null;
// construct our entity objects
Blob imageBlob = null;
// Create a new Blob file with mime-type "image/png"
AppEngineFile file = null;
FileWriteChannel writeChannel = null;
try {
// get input stream from file
imgStream = myFile.getInputStream();
imageBlob = new Blob(IOUtils.toByteArray(imgStream));
// create empty app engine file with mime type of uploaded file e.g.: image/png, image/jpeg
file = fileService.createNewBlobFile(myFile.getContentType());
// Open a channel to write to it
boolean lock = true;
writeChannel = fileService.openWriteChannel(file, lock);
// This time we write to the channel directly
writeChannel.write(ByteBuffer.wrap(imageBlob.getBytes()));
} catch (IOException e) {
e.printStackTrace();
}finally{
// Now finalize
try {
writeChannel.closeFinally();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// Get the url from the blob
ServingUrlOptions suo = ServingUrlOptions.Builder.withBlobKey(fileService.getBlobKey(file)).secureUrl(true);
imageUrls += imagesService.getServingUrl(suo);
imageUrls = imageUrls.replaceFirst("0.0.0.0", "127.0.0.1");
System.out.println(imageUrls);
}
return imageUrls ;
}
}
I tried and found that image service got a maximum image output of 1600x1600.
see here and search for 1600: https://developers.google.com/appengine/docs/java/images/
That applies even if you don't request for an resize.
To serve the image in original size, you shouldn't use the image service, just output directly from (e.g. blobstore)

Cannot read two consecutive files with a Windows Service using StreamReader object

I need to be able to read lines of a file with a StreamReader processed by a FileSystemWatcher in a Windows service.
I've read and tried everything that made sense online, but it still doesn't work. When I'm attahced to my Windows service process (local machine using Visual Studio 2010), the whole thing works flawlessly!
When I try to run it (on my local machine) without attaching to it and debugging it, the second file never makes it through and I get the following msg:
"The process cannot access the file 'C:\Projects\Data\VendingStats\20121213_AZM_Journey_MIS.txt' because it is being used by another process." I do not have this file open anywhere else on my machine. It is just sitting in a directory. I then copy it in a directory and the FSW takes over (and the code below).
Can someone please tell me what I need to do to get this to work? I don't know why it works fine when I'm attached to and debugging it, but it doesn't work when I send the files through without being attached and debugging it. I feel it's defeintiely something on my local box that I need to disable, etc --- I don't know.....
I noticed that the error occurs even before it gets into the "using" statement, because the second file is never copied to the temp directory for it to be processed.
I noticed in my StackTrace, I'm getting the following error:
system.io.__error.winioerror(int32 errorcode string maybefullpath)
Here is my code:
protected override void OnStart(string[] args)
{
FileSystemWatcher Watcher = new FileSystemWatcher(#"C:\Projects\Data\VendingStats");
Watcher.EnableRaisingEvents = true;
Watcher.Created += new FileSystemEventHandler(Watcher_Created);
Watcher.Filter = "*.txt";
Watcher.IncludeSubdirectories = false;
}
private void Watcher_Created(object sender, FileSystemEventArgs e)
{
try
{
string targetPath = #"C:\Temp\VendorStats";
// Use Path class to manipulate file and directory paths.
FileInfo fi = new FileInfo(e.FullPath); // full name of path & file in the FSW directory
string destFile = Path.Combine(targetPath, fi.Name);
// To copy a folder's contents to a new location:
// Create a new target folder, if necessary.
if (!Directory.Exists(targetPath))
Directory.CreateDirectory(targetPath);
// To copy a file to another location and
File.Copy(e.FullPath, destFile, true);
// Set attribute to READONLY
if (fi.IsReadOnly == false)
fi.Attributes = FileAttributes.ReadOnly;
GetCruiseLineShipName(destFile, ref cruiseLine, ref shipName);
using (StreamReader sr = new StreamReader(File.Open(destFile, FileMode.Open, FileAccess.Read, FileShare.Read)))
{
filename = e.FullPath;
//How many lines should be loaded?
int NumberOfLines = 39;
//Read the number of lines and put them in the array
for (int i = 1; i < NumberOfLines; i++)
{
ListLines[i] = sr.ReadLine();
switch (i)
{
case 3:
int idx = ListLines[i].IndexOf(":");
string timeLine = ListLines[i].Substring(idx + 1);
dt = GetDate(Convert.ToDateTime(timeLine.Substring(1)));
break;
//more code here of the same
}
}
//InsertData into database }
}
catch (Exception ex)
{
EventLog.WriteEntry("VendorStats", "Error in the Main:" + "\r\n\r\n" + ex.Message + "\r\n\r\n" + ex.InnerException);
return;
}
}
The bottom line to solving this was to put the method (that was spawned by the FileSystemWatcher) to sleep for "X" amount of seconds until Windows completely releases the resources to the previous and present files as well as the folder.
It was the FileSystemWatcher that actaully had a hold on the resources.
Here is some sample code:
private static void Watcher_Created(object sender, FileSystemEventArgs e)
{
try
{
Thread.Sleep(10000);
GetCruiseLineShipName(e.FullPath, ref cruiseLine, ref shipName);
using (StreamReader sr = new StreamReader(File.Open(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read)))
{

Resources