How to open a packaged file with WinRT - c#

I am trying to figure out how to port some .Net code that parsed an xml file to WinRT. So far, with the help of The given System.Uri cannot be converted into a Windows.Foundation.Uri, I have the below code. Still, I get stuck immediately after I create the Uri:
static readonly Uri ResourcesBase = new Uri(#"ms-resource://MyAssembly/");
public override async void Load()
{
Uri uri = new Uri(ResourcesBase, filePath); // filePath = "Data//world.xml";
XmlLoadSettings settings = new XmlLoadSettings() { ValidateOnParse = false };
XmlDocument xmlDoc = await XmlDocument.LoadFromUriAsync(uri, settings);
foreach (IXmlNode xmlNode in xmlDoc.ChildNodes)
{
ProcessNode(xmlNode);
}
}
I get an unhandled exception when I try to call XmlDocument.LoadFromUriAsyn(uri):
ArgumentException was unhandled by the user code - Value does not fall within the expected range.
Anyone else feel like everything is 10 times harder with WinRT?
EDIT:
I have tried all the following strings, and get the exact same error:
Uri uri = new Uri("ms-resource://MyAssembly//" + filePath);
Uri uri = new Uri("ms-resource://MyAssembly/" + filePath);
Uri uri = new Uri("d:\\projects\\crystal\\" + filePath); // A valid absolute path
Project Set Up:
Project
Properties
References
Assets
Data
world.xml
Source code...
In Code:
filePath = "Data\\world.xml";
I have also tried putting the xml file under assset\data, and just assets. Nothing seems to make a difference.
Another thing, I have the Build Action of the xml set to "Content". Is that correct? The only other thing I could imagine that it would be is "Embedded Resource" but I doubt it.
Full Exception details:
System.ArgumentException was unhandled by user code
HResult=-2147024809
Message=Value does not fall within the expected range.
Source=Windows.Data.Xml.Dom
StackTrace:
at Windows.Data.Xml.Dom.XmlDocument.LoadFromUriAsync(Uri uri, XmlLoadSettings loadSettings)
at Crystal.IO.File.XmlFileSerializer.d__1.MoveNext() in d:\Projects\Crystal\library\IO\File\XmlFileSerializer.cs:line 32
InnerException:
Download the smallest example possible to repro the issue: test_xml.zip

I finally figured it out after I looked at Windows Runtime Xml data API sample.
public override async Load()
{
var file = await GetPackagedFile("assets", "world.xml");
LoadXml(file);
}
private async void LoadXml(StorageFile file)
{
XmlLoadSettings settings = new XmlLoadSettings() { ValidateOnParse = false };
XmlDocument xmlDoc = await XmlDocument.LoadFromFileAsync(file, settings);
foreach (IXmlNode xmlNode in xmlDoc.ChildNodes)
{
//ProcessNode(xmlNode);
}
}
private async Task<StorageFile> GetPackagedFile(string folderName, string fileName)
{
StorageFolder installFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
if (folderName != null)
{
StorageFolder subFolder = await installFolder.GetFolderAsync(folderName);
return await subFolder.GetFileAsync(fileName);
}
else
{
return await installFolder.GetFileAsync(fileName);
}
}
}

Related

System.IO.FileNotFound when passing file path value to OpenXML GetCellValue()

When I pass the value from the OpenFilePicker() method back to the button click method, I can utilize a debug string and ensure that the value is not null.
However, when I pass it to the GetCellValue() method, a 'FileNotFound' exception is thrown. Utilizing a debug statement here also shows that the value is not null and returns a valid file path of "C:\Test.xlsx".
Tried changing file permissions to RWX for all, attempted different folder locations. All permissions and folders seem to have the same issue.
public async void FileSelectButton_ClickAsync(object sender, RoutedEventArgs e)
{
string filePath = await openFilePicker();
//Debug.WriteLine("result:: " + filePath);
GetCellValue(filePath, "Sheet1", "A1");
}
public async Task<string> openFilePicker()
{
var archerReportPicker = new
Windows.Storage.Pickers.FileOpenPicker();
archerReportPicker.ViewMode =
Windows.Storage.Pickers.PickerViewMode.Thumbnail;
archerReportPicker.SuggestedStartLocation =
Windows.Storage.Pickers.PickerLocationId.Downloads;
archerReportPicker.FileTypeFilter.Add(".xlsx");
archerReportPicker.FileTypeFilter.Add(".xls"); // Default extensions
Windows.Storage.StorageFile archerReport = await archerReportPicker.PickSingleFileAsync(); //Get file
if (archerReport != null)
{
// Application now has read/write access to the picked file
this.fileTextBox.Text = archerReport.Name; // Load it up and throw the data in the textbox.
var filePath = archerReport.Path;
return filePath;
}
else
{
this.fileTextBox.Text = "";
return null;
}
}
public static string GetCellValue(string fileName, string sheetName, string addressName)
{
string value = null;
// Open the spreadsheet document for read-only access.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(fileName, false)) //Line where exception is thrown
{...}
Throws System.IO.FileNotFound Exception as opposed to opening valid file path.
The issue also occurs when filePath or fileName is defined using const string '#c:\test.xlsx'
The short answer to this question is here:
https://blogs.msdn.microsoft.com/wsdevsol/2012/12/04/skip-the-path-stick-to-the-storagefile/
The gist of it is that in UWP, Storage Pickers return a non-filesystem bound Windows.Storage object. You can glean the filesystem path from the object, but because you are performing an operation on a secondary object, the fact that the user gave permissions for the first object does not apply to the second, resulting in an Access Denied condition when attempting to open the file - even if NTFS permissions allow 'Everyone' access.
This can be confirmed by monitoring the application using Process Monitor from SystemInternals.
If I discover a work-around to this issue, I will update this answer, but I will likely move away from UWP back towards a Windows Forms Application to avoid this issue entirely.

CreateFileAsync() stops debugging and never returned

Now I'm trying to make UWP application with VS2017 using C#. I use CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists) to create two files at the initial time, to open them afterwards. However it stopped during opening the second file(F5, F10, F11 buttons doesn't work during debugging). It runs cool during Creating files or opening the first file. Here is my code.
public static StorageFile GetDataFileFromLocalFolder(string fileName)
{
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("fileName missing");
}
return GetDataFileFromLocalFolderAsync(fileName).Result;
}
private static async Task<StorageFile> GetDataFileFromLocalFolderAsync(string fileName)
{
var sFolder = ApplicationData.Current.LocalFolder;
var sFile = await sFolder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
return sFile;
}
Is there any problem? Shouldn't use OpenIfExist option?
I solve this problem as avoiding await keyword.
public static async Task<StorageFile> GetDataFileFromLocalFolderAsync(string fileName)
{
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentNullException("fileName missing"); //remove hard coded string here
}
var sFolder = ApplicationData.Current.LocalFolder;
var sFileTask = sFolder.CreateFileAsync(fileName, CreationCollisionOption.OpenIfExists);
var sFile = sFileTask.AsTask().Result;
return sFile;
}
Now it works fine. but never knows why....

Can You Use URI's from a Library (PicturesLibrary) In UWP?

I'm trying to use this code to access a file's URI from the PicturesLibrary:
StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
StorageFile tpkFile = await picturesFolder.GetFileAsync("campus.tpk");
Uri tpkFileUri = new Uri(tpkFile.Path);
Debug.WriteLine("This is the tpkFile path: " + tpkFileUri);
ArcGISTiledLayer tpkLayer = new ArcGISTiledLayer(tpkFileUri);
try
{
MyMapView.Map.OperationalLayers.Add(tpkLayer);
}
catch(Exception e)
{
Debug.WriteLine("This is the Exception: " + e);
}
Which returns a URI of:
file:///C:/Users/username/Pictures/campus.tpk
But I know UWP apps only take URIs that start with ms-appx:///
My question is, how can I can I access the file at the first URI with the ms-appx:/// prefix?
Right now the code fails at this line:
ArcGISTiledLayer tpkLayer = new ArcGISTiledLayer(tpkFileUri);
Because it says the URI is not correct, so the reference to tpkLayer is null.
Copy it to your ApplicationData.Current and use ms-appdata:/// would that work for you? ms-appx:/// reference to the files in your appx which is readonly.
here you can read more about the ms-appdata schema: https://blogs.windows.com/buildingapps/2014/06/19/common-questions-and-answers-about-files-and-app-data-part-1-app-data/#j4m8ylp93K7ujk6Q.97

Dropbox.Api failing to upload large files

I am uploading files to dropbox using the following code.
I am using the nuget package Dropbox.Api and getting the exception System.Threading.Tasks.TaskCanceledException("A task was canceled.")
From this SO Question it appears to be a timeout issue.
So how do I modify the following code to set the timeout.
public async Task<FileMetadata> UploadFileToDropBox(string fileToUpload, string folder)
{
DropboxClient client = new DropboxClient(GetAccessToken());
using (var mem = new MemoryStream(File.ReadAllBytes(fileToUpload)))
{
string filename = Path.GetFileName(fileToUpload);
try
{
string megapath = GetFullFolderPath(folder);
string megapathWithFile = Path.Combine(megapath, Path.GetFileName(Path.GetFileName(filename))).Replace("\\", "/");
var updated = client.Files.UploadAsync(megapathWithFile, WriteMode.Overwrite.Instance, body: mem);
await updated;
return updated.Result;
}
catch (Exception ex)
{
return null;
}
}
}
Try creating and initializing the client like this:
var config = new DropboxClientConfig();
config.HttpClient.Timeout = new TimeSpan(hr, min, sec); // choose values
var client = DropboxClient(GetAccessToken(), config);
Reference:
http://dropbox.github.io/dropbox-sdk-dotnet/html/M_Dropbox_Api_DropboxClient__ctor_1.htm
One more thing to keep in mind is UploadAsync will not work for files larger than 150MB as per documentation. One will have to use UploadSessionStartAsync based implementation for it. I was making the mistake without realizing it and it took ages for me to fish the problem out.

Windows 8 Metro check if file exists [duplicate]

This question already has answers here:
How to check if file exists in a Windows Store App?
(10 answers)
Closed 9 years ago.
I am trying to write a routine to check if a file exists in a application package. After reading a lot on the subject it's obvious that MS forgot to put a FileExists function in the API (deliberate or not) but here is where I am at so far...
public async Task<bool> CheckFile(string filePath)
{
bool found = false;
try
{
Windows.ApplicationModel.Package package = Windows.ApplicationModel.Package.Current;
Windows.Storage.StorageFolder installedLocation = package.InstalledLocation;
StorageFile file = await installedLocation.GetFileAsync("Assets\\" + filePath);
found = true;
}
catch (System.IO.FileNotFoundException ex)
{
found = false;
}
return found;
}
and then called from:
private ImageSource _image = null;
private String _imagePath = null;
public ImageSource Image
{
get
{
if (this._image == null && this._imagePath != null)
{
Task<bool> fileExists = CheckFile(this._imagePath);
bool filefound = fileExists.Result;
string realPath = string.Empty;
if (filefound)
{
Windows.ApplicationModel.Package package = Windows.ApplicationModel.Package.Current;
Windows.Storage.StorageFolder installedLocation = package.InstalledLocation;
realPath = installedLocation + "Assets\\" + this._imagePath;
}
else
{
realPath = "http://<<my url>>/images/" + this._imagePath;
}
this._image = new BitmapImage(new Uri(realPath));
}
return this._image;
}
set
{
this._imagePath = null;
this.SetProperty(ref this._image, value);
}
}
SO basically it's a check to see if an image exists locally and if not then go get it from my website.
It all seems to work fine for the first image but then when it gets to "return this._image;" for the second image everything just freezes...
I'm just not sure what's going on here really..
Any help?
Cheers
Dean
Checking for a file and then trying to open that file is a race condition. That is, the file can be removed between the check for existence and the open. So, you shouldn't do it that way. You're right to catch the exception from GetFileAsync from your GetFile, but you should catch a FileNotFoundException and then you know the file did not exist.
Your code for CheckFile does something funny, however. You have an internal try-catch block that will swallow up all exceptions, show a message box and then set found = true no matter what happened in the try block. I don't think that's what you intend. Also, the surrounding try-catch block is not necessary as it will only be hit if creating a new MessageDialog or ShowAsync throw an exception -- that is when you set found to false -- which is not what I think you want.

Categories

Resources