PickSaveFileAndContinue: UnauthorizedAccessException on Windows 10 mobile - windows-runtime

I am using this code to let users to choose where to save a file:
var fileSavePicker = new FileSavePicker();
fileSavePicker.FileTypeChoices.Add("Pdf", new List<string>(){".pdf"});
fileSavePicker.SuggestedFileName = $"{pdfFile.Name}";
fileSavePicker.SuggestedSaveFile = pdfFile;
fileSavePicker.PickSaveFileAndContinue();
This code works fine on Windows Phone 8.1 but give me an exception (System.UnauthorizedAccessException) when running on Windows 10 mobile. How can I solve this?

When I use FileSavePicker.PickSaveFileAndContinue method in the visual, there is an error “ The FileSavePicker.PickSaveFileAndContinue() is obsolete: instead, use PickSaveFileAsync() ”. So you can use FileSavePicker.PickSaveFileAsync() method in Windows 10 mobile.
Update:
I have test Windows Phone 8.1 on Windows 10 Mobile, it was ok. The code of my project below , you can refer to.
You can also refer to this sample about FileSavePicker.
private void SaveFileButton_Click(object sender, RoutedEventArgs e)
{
// Clear previous returned file name, if it exists, between iterations of this scenario
OutputTextBlock.Text = "";
FileSavePicker savePicker = new FileSavePicker();
savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
// Dropdown of file types the user can save the file as
savePicker.FileTypeChoices.Add("Plain Text", new List<string>() { ".txt" });
// Default file name if the user does not type one in or select a file to replace
savePicker.SuggestedFileName = "New Document";
savePicker.PickSaveFileAndContinue();
}
/// <summary>
/// Handle the returned file from file picker
/// This method is triggered by ContinuationManager based on ActivationKind
/// </summary>
/// <param name="args">File save picker continuation activation argment. It cantains the file user selected with file save picker </param>
public async void ContinueFileSavePicker(FileSavePickerContinuationEventArgs args)
{
StorageFile file = args.File;
if (file != null)
{
// Prevent updates to the remote version of the file until we finish making changes and call CompleteUpdatesAsync.
CachedFileManager.DeferUpdates(file);
// write to file
await FileIO.WriteTextAsync(file, file.Name);
// Let Windows know that we're finished changing the file so the other app can update the remote version of the file.
// Completing updates may require Windows to ask for user input.
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
if (status == FileUpdateStatus.Complete)
{
OutputTextBlock.Text = "File " + file.Name + " was saved.";
}
else
{
OutputTextBlock.Text = "File " + file.Name + " couldn't be saved.";
}
}
else
{
OutputTextBlock.Text = "Operation cancelled.";
}
}

Related

Unity - Read JSON file From android [duplicate]

This is how i read my textfile in android.
#if UNITY_ANDROID
string full_path = string.Format("{0}/{1}",Application.streamingAssetsPath, path_with_extention_under_streaming_assets_folder);
// Android only use WWW to read file
WWW reader = new WWW(full_path);
while (!reader.isDone){}
json = reader.text;
// PK Debug 2017.12.11
Debug.Log(json);
#endif
and this is how i read my textfile from pc.
#if UNITY_STANDALONE
string full_path = string.Format("{0}/{1}", Application.streamingAssetsPath, path_with_extention_under_streaming_assets_folder);
StreamReader reader = new StreamReader(full_path);
json = reader.ReadToEnd().Trim();
reader.Close();
#endif
Now my problem is that i don't know how to write the file on mobile cause i do it like this on the standalone
#if UNITY_STANDALONE
StreamWriter writer = new StreamWriter(path, false);
writer.WriteLine(json);
writer.Close();
#endif
Help anyone
UPDATED QUESTION
This is the json file that it is in my streamingasset folder that i need to get
Now my problem is that i don't know how to write the file on mobile
cause I do it like this on the standalone
You can't save to this location. Application.streamingAssetsPath is read-only. It doesn't matter if it works on the Editor or not. It is read only and cannot be used to load data.
Reading data from the StreamingAssets:
IEnumerator loadStreamingAsset(string fileName)
{
string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, fileName);
string result;
if (filePath.Contains("://") || filePath.Contains(":///"))
{
WWW www = new WWW(filePath);
yield return www;
result = www.text;
}
else
{
result = System.IO.File.ReadAllText(filePath);
}
Debug.Log("Loaded file: " + result);
}
Usage:
Let's load your "datacenter.json" file from your screenshot:
void Start()
{
StartCoroutine(loadStreamingAsset("datacenter.json"));
}
Saving Data:
The path to save a data that works on all platform is Application.persistentDataPath. Make sure to create a folder inside that path before saving data to it. The StreamReader in your question can be used to read or write to this path.
Saving to the Application.persistentDataPath path:
Use File.WriteAllBytes
Reading from the Application.persistentDataPath path
Use File.ReadAllBytes.
See this post for a complete example of how to save data in Unity.
This is the way I do it without the WWW class (works for Android an iOS), hope its useful
public void WriteDataToFile(string jsonString)
{
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
if (!File.Exists(filePath))
{
File.Create(filePath).Close();
File.WriteAllText(filePath, jsonString);
}
else
{
File.WriteAllText(filePath, jsonString);
}
}

ProgressEvent.load is always the same as ProgressEvent.Total which causes the progress to fake

I'm trying to implement progress bar on a website.
The Problem:
ProgressEvent.load is always the same as ProgressEvent.Total which prevent the progress to show the real state of the upload. At the first second the xhr request does sent it looks like it finished but actually the server is still getting parts of the file.
JS:
My js code(the part of the progress) looks like that:
xhr.upload.onprogress = function (event) {
var progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
that._onProgressItem(item, progress);
};
the property lengthComputable is true.
the event.loaded is 4354707 as the event.total which is 4354707.
C# Server Side:
public async Task<FileResultViewModel> Upload(string type)
{
string ServerUploadFoler = "...";
// Verify that this is an HTML Form file upload request
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.UnsupportedMediaType));
}
// Create a stream provider for setting up output streams
var streamProvider = new MultipartFormDataStreamProvider(ServerUploadFolder);
// Read the MIME multipart asynchronously content using the stream provider we just created.
await Request.Content.ReadAsMultipartAsync(streamProvider);
string guid = String.Empty;
if (serverUploadMoveFolder != ServerUploadFolder)
{
foreach (MultipartFileData fileData in streamProvider.FileData)
{
guid = Guid.NewGuid().ToString();
string newFileName = serverUploadMoveFolder + guid + GetExtension(uploadType);
FileInfo fi = new FileInfo(fileData.LocalFileName);
fi.MoveTo(newFileName);
}
}
// Create response
return new FileResultViewModel
{
FileName = guid
};
}
Chrome debug after 1 second of upload with a file of 4.2MB:
In fiddler after the request has completed:
My questions are:
How does the browser knows the loaded size? How does it split the file to parts and based on what params?
How do the xhr.upload.onprogress function event get updated with the progress? Does it the server which report about his progress and if it is so where is it on the code because I didn't handle it.
Why doesn't the loaded property show the real size of part?

background Agent works fine in local environment but failed after app submission to app store

I have an wp8 app using PeriodicTask background Agent.
The task update the information of multiple live tiles,
using POST Client to get title and image url from my server to update the live tile.
Background agent works just fine in debugging and releasing mode. When the .xap file was deployed into my device using XAPDeployement tool, the background Agent also works perfectly.
However, it won't work after submitted to wp app store, no matter it's beta version or not.
If the app is downloaded from store, the background agent has never worked, and it is blocked by system after a few minutes.
How come it goes wrong since the XAP files are the same?
part of code:
public static Task<string> jsonPostClientTask(Dictionary<string, object> parameters, string url)
{
var results = new TaskCompletionSource<string>();
PostClient proxy = new PostClient(parameters);
try
{
proxy.DownloadStringCompleted += (sender, e) =>
{
if (e.Error == null)
{
string response = e.Result.ToString();
results.TrySetResult(response);
}
else
{
results.TrySetResult("");
results.TrySetException(e.Error);
}
};
proxy.DownloadStringAsync(new Uri(url));
}
catch
{
results.TrySetResult("");
}
return results.Task;
}
ScheduledAgent class:
protected override void OnInvoke(ScheduledTask task)
{
foreach (var tile in tileList)
{
string dataString = jsonPostClientTask(parameters, url);
//update tile in used
FlipTileData tileData = new FlipTileData()
{
BackContent = "string content",
WideBackContent = "string back content",
BackBackgroundImage = new Uri("http://xxxx.xxx/xxx.png", UriKind.RelativeOrAbsolute),
WideBackBackgroundImage = new Uri("http://xxxx.xxx/xxx.png", UriKind.RelativeOrAbsolute),
};
ShellTile primaryTile = ShellTile.ActiveTiles.First();
if (primaryTile != null)
primaryTile.Update(tileData);
}
}

Location of folders created in Windows Phone 8

Where do I find the location of the folders and text files I created in windows phone 8. Can we see it in the explorer like we search for the app data in Windows 8? I'm not using IsolatedStorage, instead Windows.Storage. I want to check if the folders and files are created as I want.
This is how I write the file
IStorageFolder dataFolder = await m_localfolder.CreateFolderAsync(App.ALL_PAGE_FOLDER, CreationCollisionOption.OpenIfExists);
StorageFile PageConfig = null;
try
{
PageConfig = await dataFolder.CreateFileAsync("PageConfig.txt", CreationCollisionOption.OpenIfExists);
}
catch (FileNotFoundException)
{
return false;
}
EDIT
try
{
if (PageConfig != null)
{
using (var stream = await PageConfig.OpenStreamForWriteAsync())
{
DataWriter writer = new DataWriter(stream.AsOutputStream());
writer.WriteString(jsonString);
}
}
}
catch (Exception e)
{
string txt = e.Message;
return false;
}
And this is how I read the file from the folder
try
{
var dataFolder = await m_localfolder.GetFolderAsync(App.ALL_PAGE_FOLDER);
var retpng = await dataFolder.OpenStreamForReadAsync("PageConfig.txt");
if (retpng != null)
{
try
{
using (StreamReader streamReader = new StreamReader(retpng))
{
jsonString = streamReader.ReadToEnd();
}
return jsonString;
}
catch (Exception)
{
}
}
}
catch (FileNotFoundException)
{
}
There are also other folders created. I dont receive any exceptions while writing but when I read the string is empty.
Windows.Storage.ApplicationData.LocalFolder(MSDN link here) is another name for Isolated Storage that is in Windows.Storage namespace. The only other location you can access is your app's install directory (and only read-only).
You can use Windows Phone Power Tools to browse what files are in your app's Isolated Storage, or the command line tool that comes with the SDK.
With the help of Windows Phone Power tools, I figured out that there was no text being written in file.
So I converted string to byte and then wrote it to the file and it works! Don't know why the other one does not work though..
using (var stream = await PageConfig.OpenStreamForWriteAsync())
{
byte[] fileBytes = System.Text.Encoding.UTF8.GetBytes(jsonString);
stream.Write(fileBytes, 0, fileBytes.Length);
}
The command line tool that comes with Windows Phone SDK 8.0 is Isolated Storage Explorer (ISETool.exe) which reside in "Program Files (x86)\Microsoft SDKs\Windows Phone\v8.0\Tools\IsolatedStorageExplorerTool" folder for default installation
ISETool.exe is used to view and manage the contents of the local folder

Direct network transfers C#

I was just curious, is it possible to have direct network transfers in c#, without local caching.
e.g.
I have response stream which represents GoogleDrive file and request stream to upload file to another GoogleDrive account.
At that momment I can download file to local pc and next upload it to the google drive. But is it possible to upload it directly from one google drive to another or, at least, start uploading before full download will be completed.
Thank
Yes you can, with Google Drive api you download file into a stream and you keep it in memory so you can upload it to another google drive account after login.
You get your token on first account and download a file keeping it in a stream.
THen you authenticate on other google drive account and upload the file using the stream.
PS: When you are inserting the file on the second drive account, instead of getting
the byte[] array reading the file from disk you get the byte array from the stream you have in memory.
File Download Example:
public static System.IO.Stream DownloadFile(
IAuthenticator authenticator, File file) {
if (!String.IsNullOrEmpty(file.DownloadUrl)) {
try {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(
new Uri(file.DownloadUrl));
authenticator.ApplyAuthenticationToRequest(request);
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK) {
return response.GetResponseStream();
} else {
Console.WriteLine(
"An error occurred: " + response.StatusDescription);
return null;
}
} catch (Exception e) {
Console.WriteLine("An error occurred: " + e.Message);
return null;
}
} else {
// The file doesn't have any content stored on Drive.
return null;
}
File insert example:
private static File insertFile(DriveService service, String title, String description, String parentId, String mimeType, String filename) {
// File's metadata.
File body = new File();
body.Title = title;
body.Description = description;
body.MimeType = mimeType;
// Set the parent folder.
if (!String.IsNullOrEmpty(parentId)) {
body.Parents = new List<ParentReference>()
{new ParentReference() {Id = parentId}};
}
// File's content.
byte[] byteArray = System.IO.File.ReadAllBytes(filename);
MemoryStream stream = new MemoryStream(byteArray);
try {
FilesResource.InsertMediaUpload request = service.Files.Insert(body, stream, mimeType);
request.Upload();
File file = request.ResponseBody;
// Uncomment the following line to print the File ID.
// Console.WriteLine("File ID: " + file.Id);
return file;
} catch (Exception e) {
Console.WriteLine("An error occurred: " + e.Message);
return null;
}
}