Error with assign StorageFile with CreateFileAsync in UWP - c#

I'm suffered from making text files with UWP.
I've experienced how to make a text file in UWP.
but when I tried to make own my program, I got some problems with Creating File. I don't know where is the reason from. the lack of my knowledge about C# class p? or misuse of builtin Class(like storageFile etc...) function?
I made my application to read files from device and save as a another file.
but It doesn't work at all.
when I use break point to figure out what is problem.
Picture1. outputFile is setted as a null
you can see i.outputFile(type StorageFile) is setted as a null. but with my intent, it shouldn't be remained as a null.
because I set its(i's) outputFile with member function called "setOutFile(StorageFolder)". you can see in the picture above.
below is my source code which handle my ClassType. it stops when meet FileIO.WriteTextAsync ... because i.outPutFile is null.
public async Task<List<string>> DoRandom(FileLists fl, StorageFolder folder)
{
FileLists retLists = new FileLists();
List<string> encodingList = new List<string>();
foreach (UploadedFile i in fl)
{
// read stream from storagefile
Stream s = await i.originFile.OpenStreamForReadAsync();
// streamreader from stream
StreamReader sr = new StreamReader(s, Encoding.ASCII);
i.setOutFile(folder);
if (sr.CurrentEncoding == Encoding.ASCII)
{
encodingList.Add("ASCII " + i.outputName);
}
string str = await sr.ReadToEndAsync();
StringBuilder stringBuilder = new StringBuilder(str);
if (Option1)
{
doOption1(stringBuilder);
}
await FileIO.WriteTextAsync(i.outputFile, stringBuilder.ToString());
if (Option1);
};
return encodingList;
}
in Uploaded Class (you can just see setOutFile function).
class UploadedFile
{
public StorageFile originFile;
public StorageFile outputFile { get; set; }
public string inputName {get; private set; }
public string outputName {get; private set; }
public string fileSz{get; private set;}
public UploadedFile(StorageFile storageFile)
{
originFile = storageFile;
inputName = storageFile.Name;
}
public async Task GetFileSz()
{
var bp = await originFile.GetBasicPropertiesAsync();
this.fileSz = string.Format("{0:n0} Byte", bp.Size);
}
public async void setOutFile(StorageFolder folder)
{
var rand = new Random();
string charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder result = new StringBuilder(13);
for (int i=0; i<13; i++)
{
result.Append(charset[rand.Next(charset.Length)]);
}
StringBuilder outputName = new StringBuilder();
outputName.Append(inputName.Substring(0, inputName.Length - 4));
outputName.Append("_");
outputName.Append(result);
outputName.Append(".txt");
this.outputName = outputName.ToString();
outputFile = await folder.CreateFileAsync(outputName.ToString(), CreationCollisionOption.ReplaceExisting);
for (int i = 0; i <= 10000; i++) // break point
i++;
}
when I insert a assignment(below) in constructor.
outputFile = storageFile;
it barely make a file in target directory with purposed fileName. but it has no data in it!!!..... I tried with below source Code but it has no data in it, either.
await FileIO.WriteTextAsync(i.outputFile, "constant String");
my app makes file with edited constructor, but it has no data in it.
I don't know what is my problem, C# Class syntax or ...what?

Thanks all of you, guys who commented on my posts.
I desperately tried to figure out what is problem, I met. I carefully read your comments and I think your advice is definitely good.
but the problem that I met was, Straightforwardly, sync,async- matter thing. I struggled with this problem with more than 5 hours, and I found the class's member function setOutfile has async function "StorageFoder.CreateFileAsync" and when the machine read that statement, It create asynchronously and begin to write some text(implemented in handler class) on It even It's not created.
...In myType Class, I changed my member function's type from async void to async Task.
public async Task setOutFile(StorageFolder folder)
{
var rand = new Random();
string charset = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
StringBuilder result = new StringBuilder(13);
for (int i=0; i<13; i++)
{
result.Append(charset[rand.Next(charset.Length)]);
}
StringBuilder outputName = new StringBuilder();
outputName.Append(inputName.Substring(0, inputName.Length - 4));
outputName.Append("_");
outputName.Append(result);
outputName.Append(".txt");
this.outputName = outputName.ToString();
if (folder != null)
{
outputFile = await folder.CreateFileAsync(outputName.ToString(), CreationCollisionOption.ReplaceExisting);
}
}
and then in handler class member function, i just added await keyword before i.setOutFile(StorageFolder ..)
public async Task<List<string>> DoRandom(FileLists fl, StorageFolder folder)
{
FileLists retLists = new FileLists();
List<string> encodingList = new List<string>();
foreach (UploadedFile i in fl)
{
// read stream from storagefile
Stream s = await i.originFile.OpenStreamForReadAsync();
// streamreader from stream
StreamReader sr = new StreamReader(s, Encoding.ASCII);
await i.setOutFile(folder) ; // wait until setOutFile ends
if (sr.CurrentEncoding == Encoding.ASCII)
{
encodingList.Add("ASCII " + i.outputName);
}
string str = await sr.ReadToEndAsync();
StringBuilder stringBuilder = new StringBuilder(str);
if (Option1)
{
doOption1(stringBuilder);
}
await FileIO.WriteTextAsync(i.outputFile, stringBuilder.ToString());
if (Option1);
};
return encodingList;
}
and It works, thanks all you guys.

Related

Loading collection view with task async method

I am trying to load thumbnails with async task method with depency service :
In my pcl page I have this :
protected override void OnAppearing()
{
Device.BeginInvokeOnMainThread(() => UserDialogs.Instance.ShowLoading("Loading...", MaskType.Black));
Task.Run(async () =>
{
directoryPath = await getThumbnails.GetBitmaps(fileInfo.FullName);
List<ThumbnailsModel> thumbnailsModels = new List<ThumbnailsModel>();
int i = 1;
Directory.GetFiles(directoryPath).ToList<string>().ForEach(delegate (string thumbnailsEmplacement)
{
thumbnailsModels.Add(new ThumbnailsModel(i, thumbnailsEmplacement));
i++;
});
CollectionViewThumbnails.ItemsSource = thumbnailsModels;
}).ContinueWith(result => Device.BeginInvokeOnMainThread(() =>
{
UserDialogs.Instance.HideLoading();
}
)
);
}
My method to get the thumbnails :
public async Task<string> GetBitmaps(string filePath)
{
//TODO-- WORK ON THIS
var appDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
string directoryPath = System.IO.Path.Combine(appDirectory, "thumbnailsTemp", System.IO.Path.GetFileNameWithoutExtension(fileName));
var stream = new MemoryStream();
using (Stream resourceStream = new FileStream(filePath, FileMode.Open))
{
resourceStream.CopyTo(stream);
}
Document document = new Document(stream);
int count = document.Pages.Count;
for(int i = 0; i<= count; i++) {
TallComponents.PDF.Rasterizer.Page page = document.Pages[0];
using (var outputStream = new FileStream(System.IO.Path.Combine(directoryPath, fileName + "Thumbnails" + i + ".png"), FileMode.Create, FileAccess.Write))
{
await Task.Run(() =>
{
page.SaveAsBitmap(outputStream, CompressFormat.Png, 5);
});
}
}
return directoryPath;
}
The problem is that my application is going in my Dependency service method then going back in my pcl OnAppearing method before the thumbnails are done and going at this line
UserDialogs.Instance.HideLoading();
Seems like you have an unhandled exception. That continuation will run even if an exception is thrown on the Task you're continuing.
This can be changed using something like TaskContinuationOptions.OnlyOnRanToCompleted (and others) in the overload for ContinueWith. The default is TaskContinuationOptions.None if not specified.
Alternatively, you can access result.Exception in your continuation if you want it to run on failure and handle it.

What's the best way to make method run async?

Hi i'm new in async programming. How can I run my method checkAvaible to run async? I would like to download 2500 pages at once if it's possible, dont wait to complete one download and start another. How can I make it?
private static void searchForLinks()
{
string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id=";
for (int i = 0; i < 2500; i++)
{
string tmp = url;
tmp += Convert.ToString(i);
checkAvaible(tmp); // this method run async, do not wait while one page is downloading
}
Console.WriteLine(listOfUrls.Count());
Console.ReadLine();
}
private static async void checkAvaible(string url)
{
using (WebClient client = new WebClient())
{
string htmlCode = client.DownloadString(url);
if (htmlCode.IndexOf("Brak takiego obiektu w naszej bazie!") == -1)
listOfUrls.Add(url);
}
}
You would not want to download 2500 pages at the same time since this will be a problem for both your client and the server. Instead, I have added a concurrent download limitation (of 10 by default). The web pages will be downloaded 10 page at a time. (Or you can change it to 2500 if you are running a super computer :))
Generic Lists (I think it is a List of strings in your case) is not thread safe by default therefore you should synchronize access to the Add method. I have also added that.
Here is the updated source code to download pages asynhcronously with a configurable amount of concurrent calls
private static List<string> listOfUrls = new List<string>();
private static void searchForLinks()
{
string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id=";
int numberOfConcurrentDownloads = 10;
for (int i = 0; i < 2500; i += numberOfConcurrentDownloads)
{
List<Task> allDownloads = new List<Task>();
for (int j = i; j < i + numberOfConcurrentDownloads; j++)
{
string tmp = url;
tmp += Convert.ToString(i);
allDownloads.Add(checkAvaible(tmp));
}
Task.WaitAll(allDownloads.ToArray());
}
Console.WriteLine(listOfUrls.Count());
Console.ReadLine();
}
private static async Task checkAvaible(string url)
{
using (WebClient client = new WebClient())
{
string htmlCode = await client.DownloadStringTaskAsync(new Uri(url));
if (htmlCode.IndexOf("Brak takiego obiektu w naszej bazie!") == -1)
{
lock (listOfUrls)
{
listOfUrls.Add(url);
}
}
}
}
It's best to convert code to async by working from the inside and proceeding out. Follow best practices along the way, such as avoiding async void, using the Async suffix, and returning results instead of modifying shared variables:
private static async Task<string> checkAvaibleAsync(string url)
{
using (var client = new HttpClient())
{
string htmlCode = await client.GetStringAsync(url);
if (htmlCode.IndexOf("Brak takiego obiektu w naszej bazie!") == -1)
return url;
else
return null;
}
}
You can then start off any number of these concurrently using Task.WhenAll:
private static async Task<string[]> searchForLinksAsync()
{
string url = "http://www.xxxx.pl/xxxx/?action=xxxx&id=";
var tasks = Enumerable.Range(0, 2500).Select(i => checkAvailableAsync(url + i));
var results = await Task.WhenAll(tasks);
var listOfUrls = results.Where(x => x != null).ToArray();
Console.WriteLine(listOfUrls.Length);
Console.ReadLine();
}

How to call async method inside a method which has return type?

This is windows phone 8.1 silverlight app.
I have a file association. For that I have a class as
class AssociationUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
//here I'm getting file ID etc..
}
// here I want to read the file content & determine the file type because,
// the case is, even same file extension can contain different type of data
switch (fileType)
{
//here I'm calling appropriate page according to type
}
}
Now the problem is MapUri is overridden method so it must have a return type. while, OpenStreamForReadAsync() is a async method. I tried Wait() method, creating new task & then calling Start(), Wait() in it but no success. Currently my code is,
class AssociationUriMapper : UriMapperBase
{
string strData = "";
public override Uri MapUri(Uri uri)
{
strUri = uri.ToString();
// File association launch
if (strUri.Contains("/FileTypeAssociation"))
{
// Get the file ID (after "fileToken=").
int nFileIDIndex = strUri.IndexOf("fileToken=") + 10;
string strFileID = strUri.Substring(nFileIDIndex);
string strFileName = SharedStorageAccessManager.GetSharedFileName(strFileID);
string strIncomingFileType = Path.GetExtension(strFileName);
fnCopyToLocalFolderAndReadContents(strFileID);
switch (fileType)
{
case ".gmm":
//determine if gmm is text
if (objGMM.fnGetGMMType() == GMMFILETYPE.TXT)
{
return new Uri("/PageReadText.xaml?data=" + strData, UriKind.Relative);
}
break;
}
}
}
async void fnCopyToLocalFolderAndReadContents(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
objFile = await SharedStorageAccessManager.CopySharedFileAsync(objLocalFolder, TEMP.gmm, NameCollisionOption.ReplaceExisting, strIncomingFileId);
using (StreamReader streamReader = new StreamReader(objFile))
{
strData = streamReader.ReadToEnd();
}
}
}
The first thing I'd do is change the logic. When the OS asks your app whether it supports a Uri mapping, it's expecting an immediate answer; it's not expecting the app to copy and read files. Usually, Uri mappings are very constant; an app either always supports one or it does not.
So, the first thing I would try to do is load all the mapping files at startup and then create the AssociationUriMapper with all the results. If this isn't possible, then you're almost certainly using Uri mappings for the wrong thing. They're not supposed to be dynamic, and it is quite possible that the OS will assume that they're not dynamic.
That said, if you want to get it working, I think the cleanest solution would be to push the asynchronous file operations to another thread and then block on that:
public override Uri MapUri(Uri uri)
{
strUri = uri.ToString();
// File association launch
if (strUri.Contains("/FileTypeAssociation"))
{
// Get the file ID (after "fileToken=").
int nFileIDIndex = strUri.IndexOf("fileToken=") + 10;
string strFileID = strUri.Substring(nFileIDIndex);
string strFileName = SharedStorageAccessManager.GetSharedFileName(strFileID);
string strIncomingFileType = Path.GetExtension(strFileName);
var strData = Task.Run(() => CopyToLocalFolderAndReadContents(strFileID)).GetAwaiter().GetResult();
switch (fileType)
{
case ".gmm":
//determine if gmm is text
if (objGMM.fnGetGMMType() == GMMFILETYPE.TXT)
{
return new Uri("/PageReadText.xaml?data=" + strData, UriKind.Relative);
}
break;
}
}
}
async Task<string> CopyToLocalFolderAndReadContentsAsync(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
objFile = await SharedStorageAccessManager.CopySharedFileAsync(objLocalFolder, TEMP.gmm, NameCollisionOption.ReplaceExisting, strIncomingFileId);
using (StreamReader streamReader = new StreamReader(objFile))
{
return streamReader.ReadToEnd();
}
}
I don't like it much, because it involves code that calls an async method synchronously. But the following should work:
class AssociationUriMapper : UriMapperBase
{
public override Uri MapUri(Uri uri)
{
strUri = uri.ToString();
// File association launch
if (strUri.Contains("/FileTypeAssociation"))
{
// Get the file ID (after "fileToken=").
int nFileIDIndex = strUri.IndexOf("fileToken=") + 10;
string strFileID = strUri.Substring(nFileIDIndex);
string strFileName = SharedStorageAccessManager.GetSharedFileName(strFileID);
string strIncomingFileType = Path.GetExtension(strFileName);
string strData = fnCopyToLocalFolderAndReadContents(strFileID).Result;
switch (fileType)
{
case ".gmm":
//determine if gmm is text
if (objGMM.fnGetGMMType() == GMMFILETYPE.TXT)
{
return new Uri("/PageReadText.xaml?data=" + strData, UriKind.Relative);
}
break;
}
}
}
async Task<string> fnCopyToLocalFolderAndReadContents(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
objFile = await SharedStorageAccessManager.CopySharedFileAsync(objLocalFolder, TEMP.gmm, NameCollisionOption.ReplaceExisting, strIncomingFileId).ConfigureAwait(false);
using (StreamReader streamReader = new StreamReader(objFile))
{
return streamReader.ReadToEnd();
}
}
}
For me, a bigger question is why would you implement a method like MapUri() such that it requires calls to asynchronous methods, and involves this kind of potentially time-consuming I/O. I mean, maybe that is in fact required here, but it just seems a bit off. Unfortunately, there's not enough context in the question for me to feel like I can offer other alternatives.
Unfortunately, there is no "pretty way" of overriding non-async methods.
The best you can do is make sure you add ConfigureAwait(false) to your async calls to make sure the SynchronizationContext doesn't flow and deadlock, and then access the Result property of the returned Task.
What i would do is change the method that reads the file to return a Task<string>:
async Task<string> CopyToLocalFolderAndReadContents(string strIncomingFileId)
{
StorageFolder objLocalFolder = Windows.Storage.ApplicationData.Current
.LocalFolder;
objFile = await SharedStorageAccessManager
.CopySharedFileAsync(objLocalFolder, TEMP.gmm,
NameCollisionOption.ReplaceExisting,
strIncomingFileId)
.AsTask().ConfigureAwait(false);
using (StreamReader streamReader = new StreamReader
(await objFile.OpenStreamForReadAsync().ConfigureAwait(false)))
{
return await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
}
And then change the call site to:
string data = CopyToLocalFolderAndReadContents(strFileID).Result;

Retrieving Images from Resource folder in C# windows form application

I am developing project in C# windows application. I am new to this technology. I declared Image variable in one class and list in another class. I want to retrieve image from Resource folder and store it in list ten times. I wrote code like this but it is returning null.
class clsAddImage
{
public Image m_imgSampleImage;
}
class clsList
{
public List<clsAddImage> lstImage = new List<clsAddImage>();
}
class clsAddImageToList
{
public void AddImgMethod()
{
clsList objlist = new clsList();
int i;
for (i = 0; i < 10; i++)
{
clsAddImage objaddimg = new clsAddImage();
objlist.lstImage.Add(objaddimg);
}
foreach (clsAddImage addimg in objlist.lstImage)
{
string path = "C:\\Users\\c09684\\Documents\\Visual Studio 2010\\Projects\\WindowsFormsAddImage\\WindowsFormsAddImage\\Resources\\Chrysanthemum.jpg";
addimg.m_imgSampleImage = Image.FromFile(path);
}
}
}
public Form1()
{
InitializeComponent();
clsAddImageToList a = new clsAddImageToList();
a.AddImgMethod();
}
I assume that you refer to a Windows8 app? In that case you can not simply program a directory to retrieve information. The user has to choose a directory manually, which you can store for future use. However, you can have access to KnownFolders (for most you have to check Capabilities in the Package.appxmanifest, e.g. Pictures Library), see http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.knownfolders for the options.
With the following task you will be able to retrieve files from a directory, I hope this helps you solving your problem:
public async Task GetFilesFromDisk()
{
StorageFolder picturesFolder = KnownFolders.PicturesLibrary;
StringBuilder outputText = new StringBuilder();
IReadOnlyList<StorageFile> fileList = await picturesFolder.GetFilesAsync();
var images = new List<BitmapImage>();
if (fileList != null)
{
foreach (StorageFile file in fileList)
{
string cExt = file.FileType;
if (cExt.ToUpper() == ".JPG")
{
Windows.Storage.Streams.IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
using (Windows.Storage.Streams.IRandomAccessStream filestream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
BitmapImage bitmapImage = new BitmapImage();
await bitmapImage.SetSourceAsync(fileStream);
}
}
} // ForEach
}
}

Make a C# Windows Store app wait for an unzip to finish

I'm trying to make an epub parsing app in a Windows Store with C#, and it won't wait for the archive (epubs are actually zip files) to finish extracting before it tries to parse the not-yet-existing table of contents. How do I make my app be a bit more patient?
I've tried making my UnZip() function return a task and having the epub constructor (epub is a class) use UnZip().Wait(), but that just freezes the app. What do I do?
Edit: Here's my relevant code:
public class epub
{
public string filename;
private StorageFolder unzipFolder;
private IList<epubChapter> _contents;
private bool _parsed = false;
public bool parsed { get { return _parsed; } } //Epub and contents are fully parsed
public epub(string newFilename)
{
_contents = new List<epubChapter>();
filename = newFilename;
UnZipFile().Wait();
getTableOfContents();
}
private async Task UnZipFile()
{
var sourceFolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
StorageFolder localFolder = ApplicationData.Current.LocalFolder;
unzipFolder = await localFolder.CreateFolderAsync(filename, CreationCollisionOption.OpenIfExists);
using (var zipStream = await sourceFolder.OpenStreamForReadAsync(filename))
{
using (MemoryStream zipMemoryStream = new MemoryStream((int)zipStream.Length))
{
await zipStream.CopyToAsync(zipMemoryStream);
using (var archive = new ZipArchive(zipMemoryStream, ZipArchiveMode.Read))
{
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (entry.Name != "")
{
using (Stream fileData = entry.Open())
{
try
{
await unzipFolder.GetFileAsync(entry.Name);
Debug.WriteLine("File at {0} already exists", entry.Name);
continue;
}
catch (FileNotFoundException)
{
Debug.WriteLine("Creating file {0}", entry.Name);
}
StorageFile outputFile = await unzipFolder.CreateFileAsync(entry.Name, CreationCollisionOption.OpenIfExists);
//Debug.WriteLine("Output file created at {0}", outputFile.Path);
using (Stream outputFileStream = await outputFile.OpenStreamForWriteAsync())
{
await fileData.CopyToAsync(outputFileStream);
await outputFileStream.FlushAsync();
}
}
if (entry.Name == "toc.ncx")
{
Debug.WriteLine("toc.ncx found in epub file; parsing it");
getTableOfContents();
}
}
}
}
}
}
}
public void getTableOfContents()
{
string contentsPath = unzipFolder.Path + #"\toc.ncx"; //The file is always called this in valid epubs
try
{
XDocument toc = XDocument.Load(contentsPath);
string nameSpace = getNameSpace(toc);
XElement navMap = firstElementNamed(toc.Root, "navMap");
parseNavPoints(navMap, nameSpace, 0);
_parsed = true;
}
catch(FileNotFoundException)
{
Debug.WriteLine("File toc.ncx was not found!");
}
}
Basically, your question seems to be: How do I call an async method from a constructor?
The short answer is that you don't, instead create an async factory method for your class.
Longer answer: As you noticed, if you call Wait(), your code will block. You can't use await, because constructors can't be async. And if you don't do anything, the constructor is going to return too early.
The solution here is to use an async factory method instead of a constructor. Something like:
private epub(string newFilename)
{
_contents = new List<epubChapter>();
filename = newFilename;
}
public static async Task<epub> CreateAsync(string newFilename)
{
var result = new epub(newFilename);
await result.UnZipFile();
result.getTableOfContents();
return result;
}
For some more information and alternative solutions, see Stephen Cleary's article about async and contructors.

Categories

Resources