Wednesday, 28 April 2010

Rebuilding CacheHelp

Ron Jacobs blogged yesterday about using the AppFabric Beta 2 Refresh and the fact that the cachehelp command seems to have disappeared. If you rely on cachehelp as much as I do, fear not! To paraphrase the start of The Six Million Dollar Man, 'we can rebuild it'...

Powershell includes a Set-Alias command, which we can use to create aliases for existing commands e.g. Set-Alias nc New-Cache. Ron helpfully provided the Powershell command we need to retrieve the AppFabric commands - Get-Command -module distributedcacheadministration - BUT you can't create an alias for a whole command-line with parameters, only for an individual command.

Fortunately we can get round this by creating a Powershell function which wrappers the commandline:
function getVelocityCommands
{
    Get-Command -module distributedcacheadministration
}

Now we can use Set-Alias GetCacheHelp getVelocityCommands to create an alias which calls the function. And we're done!

Almost...

Aliases and functions are session-based - once you close down Powershell, you'll lose them. To make them persistent, you'll need to add them to your Powershell profile. There's a great tutorial here on creating Powershell profiles. Too much work? Then download this profile, which imports the AppFabric commands and creates the cachehelp alias for you.

Monday, 26 April 2010

AppFabric For .Net 4.0

So a fortnight ago .NET and VS2010 were released, and shortly after that I tried to install the AppFabric Beta 2 release on my laptop. No go - Beta 2 has a dependency on the .NET 4 Release Candidate and will not install on the .NET 4.0 RTM release. I emailed Ron Jacobs (who has made the mistake of being associated with AppFabric and being contactable) about this and asked when we'd see a release that ran on the .NET 4.0 RTM release. He answered me and then wrote up this blog (and when he talks about emails rolling in, it's mine he quotes so I'm slightly suspicious of how many he really got about this), which says that .NET developers who want to use AppFabric will have to stay on the .NET 4.0/VS2010 RC versions until an unspecified time between now and the end of June when AppFabric will RTM. I can't say that I was hugely impressed with this:

So I was quite surprised today to look at Alvin Ashcraft's Dew Drop and find:
Which appears to be AppFabric Beta 2 rebuilt for .NET 4.0 RTM. I haven't tested it yet, but I've installed it and can confirm it installs OK onto a Windows 7 machine with .NET 4.0 RTM.

There's nothing yet about this on either Ron Jacob's blog, the Velocity blog or the .NET Endpoint blog. And I'd like Microsoft to explain their change of heart - right now, I'm interpreting it as being that AppFabric may miss it's RTM deadline of 30th June. But someone should feel free to tell me different.

Tuesday, 20 April 2010

Building A PageStatePersister With AppFabric

One of my favourite demos to do at user group sessions is to show off how you can use the SessionPageStatePersister to store page state information (Viewstate and Controlstate) on the server in Session state instead of round-tripping it to the client. But yesterday it occurred to me that you could do the same thing quite easily with AppFabric caching*.

ASP.NET has shipped with two page state persistence mechanisms since ASP.NET 2.0 was released - HiddenFieldPageStatePersister, which is the one used by default and produces those <input id="__VIEWSTATE" type="hidden" value="AnEnormousBase64EncodedTree" /> tags that we all hate so much, and SessionPageStatePersister, which instead stores the state on the web server in Session state and cuts out the roundtripping. To use the SessionPageStatePersister you need to write an Adapter class and a .browser file:

using System.Web.UI;
using System.Web.UI.Adapters;

namespace Adapter
{
    public class Adapter: System.Web.UI.Adapters.PageAdapter
    {
        public override PageStatePersister GetStatePersister()
        {
            return new SessionPageStatePersister(this.Page);
        }
    }

<browser refID="default">
    <controladapters>
        <adapter controltype="System.Web.UI.Page">
            adapterType="Adapter.Adapter" />
    </controladapters>
</browser>

SessionPageStatePersister is built into the .NET Framework, so our adapter can just new it up and return it in the GetStatePersister function. If we want to build a PageStatePersister with AppFabric, however, we've got a bit more work to do. We need a class that inherits from PageStatePersister so we can implement the Save and Load methods.

using System.Web.UI;
using System.Web.UI.WebControls;

namespace AppFabricPageStatePersister
{

    public class Persister : System.Web.UI.PageStatePersister
    {
        public Persister(Page page) : base(page)
        {
        }


        private const string HiddenFieldId = "StateIdHiddenField";


        public override void Load()
        {
            // Read page's incoming state Id from hidden field
            string stateIdString = Page.Request.Form[HiddenFieldId];


            Pair cachedState = (Pair) CacheHelper.Get(stateIdString);


            ViewState = cachedState.First;
            ControlState = cachedState.Second;
        }


        public override void Save()
        {
            Pair statePair;


            // Build a Pair from the Page's View- and ControlState
            statePair = new Pair(ViewState, ControlState);


            // Generate a new ID to use as the key for storing in the cache
            Guid stateId = Guid.NewGuid();


            // Put the Pair in the cache
            CacheHelper.Put(stateId.ToString(), statePair);


            // Write the key out into the page in a hidden field so we can get it back later
            Page.ClientScript.RegisterHiddenField(HiddenFieldId, stateId.ToString());
        }
    }
}

CacheHelper is an abstraction over AppFabric so my Persister class isn't cluttered with calls to the AppFabric objects:

using System.Web.Configuration
using Microsoft.ApplicationServer.Caching;

namespace AppFabricPageStatePersister
{
    class CacheHelper
    {
         public static object Get(string Key)
         {
            DataCacheFactory factory;
            DataCache cache;
            string cacheName;
            factory = new DataCacheFactory();
            cacheName = WebConfigurationManager.AppSettings["StatePersistenceCacheName"].ToString();
            cache = factory.GetCache(cacheName);
            return cache.Get(Key);
       }

       public static void Put(string Key, object Value)
       {
            DataCacheFactory factory;
            DataCache cache;
            string cacheName;

            factory = new DataCacheFactory();
            cacheName = WebConfigurationManager.AppSettings["StatePersistenceCacheName"].ToString();
            cache = factory.GetCache(cacheName);

            cache.Put(Key, Value);
        }
    }
}

The adapter is straightforward - like the SessionPageStatePersister adapter, all it needs to do is return a new instance of AppFabricPageStatePersister, and the .browser file just needs to point at AppFabricPageStatePersister.Adapter.

namespace AppFabricPageStatePersister

{
    public class Adapter : System.Web.UI.Adapters.PageAdapter
    {
        public override System.Web.UI.PageStatePersister GetStatePersister()
        {
            return new Persister(this.Page);
        }
    }
}

<browser refID="default">

    <controlAdapters>
        <adapter controlType="System.Web.UI.Page"
adapterType="AppFabricPageStatePersister.Adapter" />
    </controlAdapters>
</browser>
Simples.

Download this demo code: C# VB

* Yes, I know you could put your Session state in AppFabric and continue to use the SessionPageStatePersister but I'm assuming you can't/don't want to use Session state.