ichi.co.uk

Tag Results

4 posts tagged csharp

Storage Helper for WinRT (Win8 Metro) in C#

Windows 8 Metro Storage Helper

I’m currently coding a Windows 8 Metro app version of a Windows Phone 7.5 Mango app I previously made. There are quite a few differences in the code and one of the first stumbling blocks I hit was the lack of Isolated Storage in WinRT. There are some ways of making shared libraries compatible,  but I wanted to learn the new ways of doing things. One of the things I need to do is store POCOs to storage for caching and while having a quick search to see if someone had any examples, I came across Generic Object Storage Helper for WinRT by Jamie Thomson, which was a great help. The code is out of date now however as it was written for the Developer Preview and I’m coding against the Consumer Preview. Also the example also isn’t quite what I wanted as I want to be able to pass in a file-name each time, so I decided to modify and fix the code as well as make some changes to make it the way I like.

Here is my updated version of the class:

using System;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Windows.Storage;
using Windows.Storage.Streams;

namespace MyWinRTApp
{
    public enum StorageType { Local, Temporary, Roaming }

    class IsoStorage<T>
    {
        private ApplicationData appData = Windows.Storage.ApplicationData.Current;
        private XmlSerializer xmlSerializer;
        private StorageFolder storageFolder;
        private StorageType storageType;
        public StorageType StorageType {
            get { return storageType; }
            set
            {
                storageType = value;
                // set the storage folder
                switch (storageType)
                {
                    case StorageType.Local:
                        storageFolder = appData.LocalFolder;
                        break;
                    case StorageType.Temporary:
                        storageFolder = appData.TemporaryFolder;
                        break;
                    case StorageType.Roaming:
                        storageFolder = appData.RoamingFolder;
                        break;
                    default:
                        throw new Exception(String.Format("Unknown StorageType: {0}", storageType));
                }
            }
        }

        public IsoStorage() : this(StorageType.Local) {}
        public IsoStorage(StorageType type)
        {
            xmlSerializer = new XmlSerializer(typeof(T));
            StorageType = type;
        }

        /// <summary>
        /// Saves a serialized object to storage asynchronously
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="obj"></param>
        public async void SaveAsync(string fileName, T data)
        {
            try
            {
                if (data == null)
                    return;
                fileName = AppendExt(fileName);
                var file = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
                var writeStream = await file.OpenAsync(FileAccessMode.ReadWrite);
                var outStream = Task.Run(() => writeStream.AsStreamForWrite()).Result;
                xmlSerializer.Serialize(outStream, data);
                writeStream.Dispose();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// Delete a file asynchronously
        /// </summary>
        /// <param name="fileName"></param>
        public async void DeleteAsync(string fileName)
        {
            try
            {
                fileName = AppendExt(fileName);
                var file = await GetFileIfExistsAsync(fileName);
                if (file != null)
                    await file.DeleteAsync();
            }
            catch (Exception)
            {
                throw;
            }
        }

        /// <summary>
        /// At the moment the only way to check if a file exists to catch an exception... :/
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private async Task<StorageFile> GetFileIfExistsAsync(string fileName)
        {
            try
            { return await storageFolder.GetFileAsync(fileName); }
            catch
            { return null; }
        }

        /// <summary>
        /// Load a given filename asynchronously
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public async Task<T> LoadAsync(string fileName)
        {
            try
            {
                fileName = AppendExt(fileName);
                StorageFile file = null;
                file = await storageFolder.GetFileAsync(fileName);
                IRandomAccessStream readStream = await file.OpenAsync(FileAccessMode.Read);
                Stream inStream = Task.Run(() => readStream.AsStreamForRead()).Result;
                return (T)xmlSerializer.Deserialize(inStream);
            }
            catch (FileNotFoundException)
            {
                //file not existing is perfectly valid so simply return the default 
                return default(T);
                //throw;
            }
            catch (Exception)
            {
                //Unable to load contents of file
                throw;
            }
        }

        /// <summary>
        /// Appends the file extension to the given filename
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        private string AppendExt(string fileName) {
            if (fileName.Contains(".xml"))
                return fileName;
            else
                return string.Format("{0}.xml", fileName);
        }
    }
}

It seems that at the moment, there is no way to check if a file exists without using a try/catch block, but I expect that will be sorted in the final release. 

Saving an Object

Saving a POCO (any serializable object) is as simple as:

            var forecast = new Forecast { Date = DateTime.Now, Type = FeedType.Daily };
            var isoStorage = new IsoStorage<Forecast>(StorageType.Local);
            isoStorage.SaveAsync("daily", forecast);

You could also save a generic list by doing something like

            var isoStorage = new IsoStorage<List<Forecast>>(StorageType.Local);

Retrieving an Object

Retrieving a POCO is equally easy:

            var isoStorage = new IsoStorage<Forecast>(StorageType.Local);
            Forecast forecast = await isoStorage.LoadAsync("daily");

I hope that helps someone. Please feel free to leave feedback or comments below. Big thanks go out to Jamie Thomson for the initial code that I modified.

Getting an Alexa Rank programmatically in C#

As part of a project I’m working on, I needed to lookup the Alexa Traffic Rank for a domain programmatically. I found the URL the toolbar uses and wrote function to parse the XML and return the value, which I thought I’d share in case it saves someone else 15 minutes of their life… 

private int GetAlexaRank(string domain)
{
    var alexaRank = 0;
    try
    {
        var url = string.Format("http://data.alexa.com/data?cli=10&dat=snbamz&url={0}", domain);

        var doc = XDocument.Load(url);

        var rank = doc.Descendants("POPULARITY")
        .Select(node => node.Attribute("TEXT").Value)
        .FirstOrDefault();

        if (!int.TryParse(rank, out alexaRank))
            alexaRank = -1;

    }
    catch (Exception e)
    {
        return -1;
    }

    return alexaRank;
}

You’ll need to import System.Xml.Linq

HttpWebRequest causes System.NotSupportedException’ occurred in System.Windows.dll.

When using HttpWebRequest asynchronously in a Windows Phone 7 app, the console in Visual Studio was outputting:

A first chance exception of type 'System.NotSupportedException' occurred in System.Windows.dll

The fix was basically adding AllowReadStreamBuffering = true to the HttpWebRequest object. For example:

var request = HttpWebRequest.CreateHttp(feed.Url);
request.AllowReadStreamBuffering = true;

This error didn’t cause my app to crash or any other problems other than the “first chance exception”, so it might be a bug. According to Microsoft, the default value for AllowReadStreamBuffering is true, so I’m not sure why this fixes the problem, but it worked for me.