In memory cache for Silverlight 2 and 3

I’ve seen some people talking about Silverlight Caching on the Silverlight forum. And because there’s no solution that can be compared to for example the ASP.NET solution for Caching. Of course it’s not that difficult to keep some data in a simple reference, just a variable, maybe on global maybe on class level. But yes, if you want a little bit more advanced Cache which supports the expiring of data you’ll need something different.

For the general purpose of caching data which can expire after a certain timespan I wrote this solution that can be used in Silverlight 2 and 3. You can view the whole code at the end of this article.

Adding and getting data from Cache

I wanted a solution that could work with general objects the way I work in this example.

Cache.Current.Add("Testkey", 10, TimeSpan.FromMinutes(2));
object cacheData = Cache.Current.Get("Testkey");
if(cacheData!=null)
{
    int cacheDataTyped = (int) cacheData;
}

In those situations you will have to cast the data to the required Type or Structure. This works fine, we’ve done this before while accessing the ASP.NET Cache. But sometimes you’ll want to have it typed immediately. So I want to be able to use this as well.

User user = GetUser();
Cache.Current.Add("Testkeytyped", user, TimeSpan.FromMinutes(4));
User userFromCache = Cache.Current.Get<User>("Testkeytyped");

So I had to add a Generic function Get and a none Generic function Get. I did this, and the code above works fine indeed.

But what about expiring data?

To expire data I wanted to provide a TimeSpan while adding the item to the cache. The first solution I thought of was to remove items upon get if it’s no longer valid. But in the end I thought what if the amount of data is large, in those cases you want it removed as soon as it is expired. So I found a different solution. By making use of the Timer class in Silverlight. I want the timer to tick every minute, and on tick I want it to clean the cache. So the current solutions cleans up items in the cache every minute. And upon getting of items it will check if the item is still valid or not.

Please feel free to use this is solution. It’s not thread-safe, but you can add thread-safe support yourself if you want to.

/// <summary>
/// Class supports in memory cache for Silverlight applications. Silverlight 2 and 3 are supported.
/// Each minute the cache items are iterated for validility, invalid cache items are removed.
/// </summary>
public class Cache : IDisposable
{
    public static Cache Current = new Cache();
    private readonly IDictionary<string, CacheItem> _cacheItems = new Dictionary<string, CacheItem>();

    private readonly TimeSpan _period = TimeSpan.FromMinutes(1);
    private readonly TimeSpan _startTimeSpan = TimeSpan.Zero;
    private readonly TimeSpan _stopTimeSpan = TimeSpan.FromMilliseconds(-1);
    private readonly Timer _timer;
    private TimerState _state = TimerState.Stopped;

    private Cache()
    {
        _timer = new Timer(CleanUpItems, this, _stopTimeSpan, _period);
    }

    /// <summary>
    /// All the CacheItems are in a Dictionary
    /// </summary>
    public IDictionary<string, CacheItem> CacheItems
    {
        get { return _cacheItems; }
    }

    /// <summary>
    /// Get full CacheItem based on key.
    /// </summary>
    /// <param name="key">The key for which a CacheItem is stored.</param>
    /// <returns>The CacheItem stored for the given key, if it is still valid. Otherwise null.</returns>
    public CacheItem this[string key]
    {
        get
        {
            if (CacheItems.ContainsKey(key))
            {
                CacheItem ci = CacheItems[key];
                if (ci.IsValid())
                    return CacheItems[key];
            }
            return null;
        }
        set { CacheItems[key] = value; }
    }

    #region IDisposable Members

    public void Dispose()
    {
        _timer.Dispose();
    }

    #endregion

    /// <summary>
    /// Get data typed directly for given key.
    /// </summary>
    /// <typeparam name="T">The Type for which the data is set. If the type is wrong null will be returned.</typeparam>
    /// <param name="key">The key for which a CacheItem is stored.</param>
    /// <returns>The data typed for the given key, if it is still valid. Otherwise null.</returns>
    public T Get<T>(string key) where T : class
    {
        CacheItem item = this[key];
        if (item != null)
            return item.GetData<T>();
        return null;
    }

    /// <summary>
    /// Get data untyped directly for given key.
    /// </summary>
    /// <param name="key">The key for which a CacheItem is stored.</param>
    /// <returns>The data untyped for the given key, if it is still valid. Otherwise null.</returns>
    public object Get(string key)
    {
        CacheItem item = this[key];
        if (item != null)
            return item.GetData();
        return null;
    }

    private void StartTimer()
    {
        if (_state == TimerState.Stopped)
        {
            _timer.Change(_startTimeSpan, _period);
            _state = TimerState.Started;
        }
    }

    private void StopTimer()
    {
        if (_state == TimerState.Started)
        {
            _timer.Change(_stopTimeSpan, _period);
            _state = TimerState.Stopped;
        }
    }

    /// <summary>
    /// Clean up items that are not longer valid.
    /// </summary>
    /// <param name="state">Expect state to be the cache object.</param>
    private static void CleanUpItems(object state)
    {
        var cache = state as Cache;
        if (cache != null)
        {
            List<KeyValuePair<string, CacheItem>> itemsToRemove =
                cache.CacheItems.Where(i => !i.Value.IsValid()).ToList();
            foreach (var item in itemsToRemove)
            {
                cache.CacheItems.Remove(item.Key);
            }
            if (cache.CacheItems.Count == 0)
                cache.StopTimer();
        }
    }

    /// <summary>
    /// Add a new item to the cache. If the key is already used it will be overwritten. 
    /// </summary>
    /// <param name="key">The key for which a CacheItem is stored.</param>
    /// <param name="value"></param>
    public void Add(string key, CacheItem value)
    {
        if (_cacheItems.ContainsKey(key))
            _cacheItems.Remove(key);
        _cacheItems.Add(key, value);
        StartTimer();
    }

    /// <summary>
    /// Add a new item to the cache. If the key is already used it will be overwritten. 
    /// </summary>
    /// <param name="key">The key for which a CacheItem is stored.</param>
    /// <param name="data">The data to cache.</param>
    /// <param name="validDuration">The duration of the caching of the data.</param>
    public void Add(string key, object data, TimeSpan validDuration)
    {
        Add(key, new CacheItem(data, validDuration));
    }

    /// <summary>
    /// Removes the item for the given key from the cache.
    /// </summary>
    /// <param name="key">The key for which a CacheItem is stored.</param>
    /// <returns></returns>
    public bool Remove(string key)
    {
        bool remove = _cacheItems.Remove(key);
        if (_cacheItems.Count == 0)
            StopTimer();
        return remove;
    }

    #region Nested type: TimerState

    /// <summary>
    /// Used for determing TimerState
    /// </summary>
    private enum TimerState
    {
        Stopped,
        Started
    }

    #endregion
}

/// <summary>
/// Defines an item that's stored in the Cache.
/// </summary>
public class CacheItem
{
    private readonly DateTime _creationDate = DateTime.Now;

    private readonly TimeSpan _validDuration;

    /// <summary>
    /// Constructs a cache item with for the data with a validity of validDuration.
    /// </summary>
    /// <param name="data">The data for the cache.</param>
    /// <param name="validDuration">The duration for the data being valid in the cache.</param>
    public CacheItem(object data, TimeSpan validDuration)
    {
        _validDuration = validDuration;
        Data = data;
    }

    /// <summary>
    /// The data in the Cache.
    /// </summary>
    public object Data { set; private get; }

    /// <summary>
    /// Gets the Data typed.
    /// </summary>
    /// <typeparam name="T">The Type for which the data is set. If the type is wrong null will be returned.</typeparam>
    /// <returns>The data typed.</returns>
    public T GetData<T>() where T : class
    {
        return Data as T;
    }

    /// <summary>
    /// Gets the Data untyped.
    /// </summary>
    /// <returns>The data untyped.</returns>
    public object GetData()
    {
        return Data;
    }

    /// <summary>
    /// Check if the Data is still valid.
    /// </summary>
    /// <returns>Valid if the validDuration hasn't passed.</returns>
    public bool IsValid()
    {
        return _creationDate.Add(_validDuration) > DateTime.Now;
    }
}

Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.

Silverlight 3 – WebClient, WebRequest and WCF calls using Credentials?

It’s already a long time ago I wrote some articles about the missing feature of passing credentials while doing a WebRequest, WebClient or WCF call. We now have ourselves Silverlight 3 Beta, it looks like we’re getting support for Credentials at last. I can now write the following code which is seen as valid. It compiles as well…
var webClient = new WebClient();
webClient.Credentials =
    new NetworkCredential("Administrator", "p@ssw0rd");
webClient.DownloadStringCompleted +=
    webClient_DownloadStringCompleted;
webClient.DownloadStringAsync(
    new Uri("SomeData.xml", UriKind.Relative));
But does it work? Not yet, sadly. Right now we will get an exception… image The inner exception is a NotImplementedException.
{System.NotImplementedException: This property is not implemented by this class.
   at System.Net.WebRequest.set_Credentials(ICredentials value)
   at System.Net.WebClient.GetWebRequest(Uri address)
   at System.Net.WebClient.DownloadStringAsync(Uri address, Object userToken)}
What does this mean? We don’t know anything yet. The only thing we can do is speculate about a feature coming in Silverlight 3, Credentials for WebRequests. I could find the usage of ICredentials inside WebRequest and WebClient. It’s not near implementation in WCF Clients yet, but we can hope for this to be implemented as well. Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.

Silverlight 3 – Out of browser support

In the era of Silverlight 2 there were a few initiatives to get Silverlight working outside the browser. Although those were basically applications that hosted a Webbrowser component inside the application which was the host for the Silverlight application. Silverlight 3 has out of browser support natively. This article explains what can be done, and what can’t be done by using this feature. Everything is based on the first Beta of Silverlight 3.

There still is some work that needs to be done in making the exceptions informational. I tried to bring my Silverlight Application out of the browser, but I didn’t have the necessary information in the appmanifest.xml yet.

image

I did change the appmanifest.xml to be like this.

<Deployment
		xmlns="http://schemas.microsoft.com/client/2007/deployment" 
		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
	<Deployment.Parts> 
	</Deployment.Parts> 
	<Deployment.ApplicationIdentity> 
		<ApplicationIdentity
			ShortName="MM Silverlight 3 Experiments" 
			Title="MM - Experiments"> 
			<ApplicationIdentity.Blurb>This application is meant for handling experiments in Silverlight.
			</ApplicationIdentity.Blurb> 
		</ApplicationIdentity> 
	</Deployment.ApplicationIdentity> 
</Deployment>

After I tried to bring it out of the browser with this code.

App.Current.Detach();

I got this window, asking me if I want a short cut on the desktop and start menu.

image

This is what it looks like when running in the browser.

image

This is what it looks like when running outside the browser.

image

Out of browser Javascript or HTML Dom manipulation?

I think it’s really interesting to know if Javascript is supported out of the browser. Because when in the ages of Silverlight 2 I called Javascript every once in a while because I was trying to do something that wasn’t supported in Silverlight. But be careful, Javascript isn’t supported in out of browser mode. You will get an error similar to this. The same goes for HTML Dom manipulation, it’s not supported as well.

image

Are we online or offline?

You can very easily get the current state of the network connection by using this code:

NetworkInterface.GetIsNetworkAvailable();

If you want to detect changes in the state of the network connection you can make use of the NetworkAddressChanged event.

NetworkChange.NetworkAddressChanged += 
	(sender, args) => 
		Dispatcher.BeginInvoke(() => 
			{ 
				stateTextBlock.Text = string.Format("Online:{0}", NetworkInterface.GetIsNetworkAvailable()); 
			});

I test this and it really works. I remember I tried creating a listener for changes in the network connection, but it never made it ;-).

Auto-update

One of the features that’s supported is the auto-update feature. Yes this is really auto-update. You cannot stop the update from happening right now. One of the things that’s important to know though is how it’s actually implemented. It’s actually making use of metadata that’s retrieved inside the HttpResponse. To be precise it’s making use of the ETag field.

Because it’s making use of the ETag field, you’ll have to remember this will only work when running your Silverlight application inside a webserver. When accessing the generated html page, it won’t work. Because this is accessed through the local file system. Like this:

image

Besides that, I wasn’t even able to get it working using Windows Server 2008 as a client at all. When running on Windows XP as a client it is working though. And I’ve read reports it’s working Windows 7 as well. Don’t know if this is one of the beta bugs. I understood from Tim Heuer there’s a known issue with running from localhost.

Init Parameters

So what do we have left that has kind of different behavior compared to browser instances of Silverlight? The Init Params, this is a parameter that can be set in the Javascript or as param in the object used for initializing the Silverlight Application. The values can be read inside your application.

image

But when you try to access the values out of browser you won’t get the values you were expecting. Or at least, I’m not sure anymore what I was expecting. But in the end this doesn’t work either.

image 

Out of browser support is nice but…

I really like the out of browser support. But we have to keep in our mind what is supported and what isn’t. Javascript and Dom manipulation isn’t supported, although this seems to be logical because we are living outside the browser, a lot of workarounds for missing feature won’t work anymore. Besides that the initparams is completely useless outside the browser.

Ps. This article is cross posted on: Mark Monster’s blog and Silverlight Help.

Touch Form for Windows Mobile

When we take a look at Windows Mobile applications, we see more and more applications that need the ability to work with touch. Yes finger touch and not the touch by Stylus. The TouchFlo 3D software from HTC is a good example of such an application.

So I got an idea. A .NET Compact Framework TouchForm that recognizes some gestures.

TouchForm with Gesture Recognition

Yes I was thinking about very basic gesture recognition. I only want to recognize the following gestures:

  • Drag to North
  • Drag to East
  • Drag to South
  • Drag to West

But what is important though, is the fact that the gesture needs to be recognized. The gesture doesn’t have to be perfect is my opinion.

My idea was making use of Mathematics I learned a long time ago. Making use of the Unit Circle. By translating the start point of the dragging to (0,0) making the end point always having a position in the Unit Circle. The next step was the calculation of the angle inside the Unit Circle. We could basically use the following translation:

  • East (0 or 360 degrees)
  • North (90 degrees)
  • West (180 degrees)
  • South (270 degrees)

But of course I wanted to calculate everything instead of using a translation table. It took me some time to completely understand the mathematics again (I haven’t used this Mathematics for almost 10 years). Using the combination of both Sinus and Cosines to determine the real angle based on coordinates.

After the angle was calculated I want to ensure that the users gesture is also recognized when their dragging isn’t exact 90 degrees for example but might be 85 degrees or 95 degrees as well.

You can see a resulting example in this Silverlight Video. This example is just counting the gestures and showing the amount in labels. The center label is used for unrecognized gestures.

You can easily use this code. Just make sure you inherit your own form from TouchForm instead of the normal Form. Beside that you can attach a listener to the GestureRecognized event.

public partial class MyTouchForm : MM.Touch.TouchForm

{

    private int amountOfEast;

    private int amountOfNorth;

    private int amountOfNotRecognized;

    private int amountOfSouth;

    private int amountOfWest;

 

    public MyTouchForm()

    {

        InitializeComponent();

        GestureRecognized += MyTouchForm_GestureRecognized;

    }

 

    private void MyTouchForm_GestureRecognized(object sender, GestureRecognizedEventArgs e)

    {

        if (e.Gesture == MM.Touch.GestureType.NotRecognized)

            amountOfNotRecognized++;

        else if (e.Gesture == MM.Touch.GestureType.North)

            amountOfNorth++;

        else if (e.Gesture == MM.Touch.GestureType.East)

            amountOfEast++;

        else if (e.Gesture == MM.Touch.GestureType.South)

            amountOfSouth++;

        else if (e.Gesture == MM.Touch.GestureType.West)

            amountOfWest++;

 

        northLabel.Text = amountOfNorth.ToString();

        eastLabel.Text = amountOfEast.ToString();

        southLabel.Text = amountOfSouth.ToString();

        westLabel.Text = amountOfWest.ToString();

        notRecognizedLabel.Text = amountOfNotRecognized.ToString();

    }

}

You can download the source code here. Please let me know if you’re using this library in your project.