Showing posts with label c#. Show all posts
Showing posts with label c#. Show all posts

Sunday, 14 August 2016

UnauthorizedAccessException when deleting local files

While coding the first update for My Daily Wallpaper, I wanted to tackle some of the bugs reported by my users. According to the Windows Dev Dashboard, the top bug (by a long shot) was an UnauthorizedAccessException. Based on the logs this exception was caused by the wallpaper manager, which handles the downloading and setting of wallpapers based on user settings, where it would attempt to delete the old wallpaper.

foreach (StorageFile file in files)
{
    if (file.Name.StartsWith(LockscreenManager.OriginalFilenamePrefix, StringComparison.OrdinalIgnoreCase))
    {
        await file.DeleteAsync();
    }
}

The odd thing was, this error didn't occur all of the time and didn't have any clues as to why it did happen when it did.

I was stumped.

So I honed my Google-fu and managed to stumble upon a MS forum post which sounded a lot like mine.

It turns out, that when you reference a local file via the Image control in xaml, a lock is put on the file.

<Image source="Path/To/Local/File" />

This lock doesn't even seem to be taken off for while after navigating away from the page that includes said Image control.

The result - an UnauthorizedAccessException when attempting to delete the local file.

My solution to this problem is to use a converter to create the Source for the Image control by getting the file stream and loading it into a BitmapImage.

public class ImageSourceConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        string path = value as string;

        if (String.IsNullOrEmpty(path) == false)
        {
            var storageFile = StorageFile.GetFileFromPathAsync(path).AsTask().Result;

            var imageStream = storageFile.OpenStreamForReadAsync().Result;

            BitmapImage imgSource = new BitmapImage();

            imgSource.SetSource(imageStream.AsRandomAccessStream());

            return imgSource;
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

Friday, 27 May 2016

Picasa Photo Hub for Windows 10 Is Finally Out



After months of gruelling work, Picasa Photo Hub is now ready and released for Windows 10 Desktop and Mobile!

This has taken a long time as while the last update for Picasa Photo Hub laid the ground work for this upgrade, the UI has been re-written from the ground up. This means that the Windows 10 version of the app now includes:

- Viewing photos and albums from within the app itself
- Sharing photos manually makes use of the background transfer service so you don't have to wait around for them to be uploaded.
- Drag and Drop photos into the app to start uploading them into your collection (Desktop Only)
- Search your photos within the app like you can on other platforms. Try searching for "food" and see what photos come up :)

But unfortunately, with this update some features are going away. Not because I didn't have time to implement them, but because Google have announced that they are retiring the Picasa services in favour of Google Photos. This happened smack bang in the middle of development and I was torn whether to carry on with the update, or to just leave Picasa Photo Hub to die. I decided that even though the service was being retired, what I was learning during development could be used in future applications. I also felt like the users of the app deserved it to work as well as possible on Windows 10. This announcement is also the reason why the UI for the Windows Phone 8.1 version has remained untouched, and will largely be the same app you already know.

However, along with Google's announcement, they have also removed the following features which have been reflected in the application:

- Commenting on photos
- Replacing photos
- Deleting Photos

So what does the future hold for Picasa Photo Hub? If a public way for interacting with Google Photos arrives, which could happen with I/O development conference just around the corner, then the app may evolve into a Google Photos application. But for now, I have decided that development on Picasa Photo Hub will be limited to bug fixes going forward.

It's been a great ride for the app, and who knows, the application may live on in some form in the future...

Monday, 16 March 2015

Picasa Photo Hub Update

Thought it was about time for another Picasa Photo Hub update!

The upgrading in preparation for the next Windows is coming along nicely. I've upgraded most of it so that it's now using my unified portable library, along with using portable class libraries within the application itself as much as possible. This means that when the time comes to upgrade it to use all of the nice new unannounced features of Windows 10, the upgrade will be easier. It also means I don't have to maintain two internal libraries for my apps (one for Silverlight and one "Universal" apps).

This upgrade is also necessary to ensure that all of your personal data is kept in tact when the upgrade happens, as it's using some technology that has been basically deprecated (LINQ to SQL). In doing the upgrade however, I've managed to get a dormant feature working which will help with all of you guys that love tweaking your photos...


In the meantime though, I thought I would release an update to tide you over until then. This update fixes some errors reported by you as well as adding some extra debugging information to try and fix some of the other issues. They include:
  • Updated background task to check if the user is authenticated, and report issue to user if they're not.
  • Updated error logging of album picker to provide more information.
  • Made enhancements to improve background resizing of images.
  • Fixed issue where background task wasn't getting rescheduled.
  • Fixed issue where pending upload page wasn't displaying items when navigated from toast.
  • Fixed misc reported defects.
The update is live now, so grab it while it's hot!

Wednesday, 21 August 2013

Form Posts and the BackgroundTransferService


At the time of getting my Windows phone I was the owner of an app membership which at the time allowed me to develop apps for the phone. I wanted to create an app that interacted with a personal file server, which allowed files to be uploaded to it via a form post online. I achieved this by using WebRequest objects, but due to the limitation of Windows phone apps this meant that I had to stay within the app in order to complete the upload, which was not ideal. Then Mango came out and with it the BackgroundTransferService, which allowed uploads and downloads to happen regardless of the state of the app that initiated them. So I set out to upgrade my app to upload the files via this new background service, but couldn't for the life of me to get it to work so I gave up. My app membership then ran out, meaning that I could no longer use the app anyway and the code just became a folder on my computer gathering virtual dust...

Fast forward to a few weeks ago (strangest statement ever) and Microsoft announce that anyone can develop and deploy up to two apps on any one phone, for free. So, I decided to redesign my application from the ground up and starting by attempting to conquer the BackgroundTransferService once again. I started by googling (or binging, yahooing, asking, etc) my problem to see if anyone had had success in this area as a lot can happen in a few years. No one had. I then manged to find a post detailing MY EXACT PROBLEM. My face lit up. Was my search finally over? I scrolled to the bottom for an answer. No answer. I looked to see who posted it. It was me when I was first having the problem. An example that in the XKCD scenario (shown above), the poster doesn't necessarily know of a solution because I knew nothing.

I decided to attempt once again the solution that the post gave me. I downloaded Fiddler, posted a file using the BackgroundTransferService, posted a file using the web form and examined the result. Not surprisingly, the BackgroundTransferService post was missing a bunch of information that was included in the web form post, and instead was just posting the raw file binary. No boundaries of anything. But why would it? I hadn't told it to. After messing around with the Headers property and about to give up, I had one final idea. One that I thought would never work because I thought it was hacky as hell. What if the stream I stated to upload was in fact the contents that are uploaded via a web form post.

using (IsolatedStorageFileStream stream = storage.CreateFile(@"shared/transfers/" + tb_Filename.Text))
{
    StringBuilder content = new StringBuilder();
    content.AppendLine(String.Format("-----------------------------{0}", boundary));
    content.AppendLine(String.Format("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"", tb_Filename.Text));
    content.AppendLine(String.Format("Content-Type: image/jpeg"));

    content.AppendLine();

    byte[] contentAsBytes = Encoding.UTF8.GetBytes(content.ToString());
    stream.Write(contentAsBytes, 0, contentAsBytes.Length);

    content.Clear();

    _selectedStream.Position = 0;

    byte[] buffer = new byte[16 * 1024];
    int read;
    while ((read = _selectedStream.Read(buffer, 0, buffer.Length)) > 0)
    {
        stream.Write(buffer, 0, read);
    }

    content.AppendLine();

    content.AppendLine(String.Format("-----------------------------{0}--", boundary));

    contentAsBytes = Encoding.UTF8.GetBytes(content.ToString());
    stream.Write(contentAsBytes, 0, contentAsBytes.Length);
}

BackgroundTransferRequest request = new BackgroundTransferRequest(new Uri(Uri.EscapeUriString(Page_Upload.UploadDestination), UriKind.Absolute));
request.UploadLocation = new Uri(@"shared/transfers/" + tb_Filename.Text, UriKind.RelativeOrAbsolute);
request.Method = "POST";
request.Tag = tb_Filename.Text;
request.TransferPreferences = TransferPreferences.AllowCellularAndBattery;

request.Headers.Add(new KeyValuePair("Content-Type", String.Format("multipart/form-data; boundary=---------------------------{0}", boundary)));
BackgroundTransferService.Add(request);

I selected a file, hit the Upload button and checked my file server. And with much surprise (although looking back I don't see why), the file was there.

So as can be seen, the BackgroundTransferService can used to upload all types of data in all types of form. You just need to know how. Or in my case try everything else.

Update: It appears this blog post may be more helpful if it includes the php code it was interacting with. So here is a stripped down version of it
<?php
 if ($_FILES["file"]["error"] > 0)
 {
  echo "Return Code: " . $_FILES["file"]["error"] . "
";
 }
 else {
  move_uploaded_file($_FILES["file"]["tmp_name"],
           "./" . $_FILES["file"]["name"]);

  echo "Successful";
 }
?>
<form action="upload_file.php" method="POST" enctype="multipart/form-data">
  File: <input type="file" name="file" />

  <input type="submit" value="Submit" />
</form>