6
votes

I have the following code in a Windows 8 C# app which fetches an image from a server and stores it:

        private async Task httpFetcher()
    {
        HttpClient httpClient = new HttpClient();
        HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Get, "http://www.example.com/fakeImageRotator.php"); // FOR EXAMPLE
        HttpResponseMessage response = await httpClient.SendAsync(request,
            HttpCompletionOption.ResponseHeadersRead);

        Uri imageUri;
        BitmapImage image = null;

        try
        {
            var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(
         "test.png", CreationCollisionOption.ReplaceExisting);
            var fs = await imageFile.OpenAsync(FileAccessMode.ReadWrite);
            DataWriter writer = new DataWriter(fs.GetOutputStreamAt(0));
            writer.WriteBytes(await response.Content.ReadAsByteArrayAsync());
            await writer.StoreAsync();
            writer.DetachStream();
            await fs.FlushAsync();
            writer.Dispose();

            if (Uri.TryCreate(imageFile.Path, UriKind.RelativeOrAbsolute, out imageUri))
            {
                image = new BitmapImage(imageUri);
            }

        }
        catch (Exception e)
        {
            return;
        }

        image1.Source = image;
    }

It appears that I randomly get errors on this particular line:

                var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(
         "test.png", CreationCollisionOption.ReplaceExisting);

It doesn't always happen, so I'm not sure how to pinpoint the issue. All the error details are here:

UnauthorizedAccessException was caught

Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)) at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at TestApp.MainPage.d__4.MoveNext() in d:\TestApp\TestApp\MainPage.xaml.cs:line 86

3

3 Answers

6
votes

Update - The "Access Denied" errors are being caused by multiple things.

The first cause has to do with the downloading of the image. It appears something in download code is holding open the file. I have simplified the download code below.

The second cause has to do with the BitmapImage object holding open the file. See this post for more info: Access Denied when deleting image file previously used in DataTemplate in WinRT

One way around the second issue is to use a stream instead of a Uri to initialize the BitmapImage.

Here is a version that works for me (your original code is also here, but commented out):

var imageFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(
  "test.png", CreationCollisionOption.ReplaceExisting);
/*
var fs = await imageFile.OpenAsync(FileAccessMode.ReadWrite);
DataWriter writer = new DataWriter(fs.GetOutputStreamAt(0));
writer.WriteBytes(await response.Content.ReadAsByteArrayAsync());
await writer.StoreAsync();
writer.DetachStream();
await fs.FlushAsync();
writer.Dispose();

if (Uri.TryCreate(imageFile.Path, UriKind.RelativeOrAbsolute, out imageUri))
{
    image = new BitmapImage(imageUri);
}
*/
var fs = await imageFile.OpenStreamForWriteAsync();
await response.Content.CopyToAsync(fs);
await fs.FlushAsync();
// you may want to have this Dispose as part of a 
// finally block (try/ catch/ finally)
fs.Dispose();

var bs = await imageFile.OpenAsync(Windows.Storage.FileAccessMode.Read);
image = new BitmapImage();
image.SetSource(bs);
...
image1.Source = image;
1
votes

I have been facing the same problem when I downloaded the pdf document to LocalFolder file and tried to display it. I can't tell reliably why this is happening, but this little hack helped me to solve this:

Instead of using

try
{
  StorageFile storage = await ApplicationData.Current.LocalFolder.CreateFileAsync(
    fileName, CreationCollisionOption.ReplaceIfExists);

  //work with file
}
catch (Exception) { ... }

I now use this:

StorageFile storage = null;
try 
{ 
  //First try to get the file
  storage = await ApplicationData.Current.LocalFolder.GetFileAsync(fileName); 
}
catch (Exception) 
{ 
  //Ignore this exception
}

try
{
  //If the storage file is still null, create it
  if (storage == null)
    storage = await ApplicationData.Current.LocalFolder.CreateFileAsync(
      fileName, CreationCollisionOption.OpenIfExists);

  //Work with file
}
catch (Exception)
{
  //Process exception
}
1
votes

If you have the option to use CreationCollisionOption.GenerateUniqueName instead of ReplaceExisting, try to use this.

At least it solved the problem for me.