Saturday, August 16, 2008

Entity Framework - Key Extension Methods

We created the following extension methods for entity framework to avoid code bloat in consuming applications when working with these key types. I hope you find them useful if you are working with the Entity Framework.

 

EntityObject

/// <summary>
/// Extension methods for EntityObject
/// </summary>
public static class EntityObjectExtensions
{

    /// <summary>
    /// Gets the original value for a modified entity object's property
    /// </summary>
    /// <returns>the value before the property was modified</returns>
    public static T GetOriginalValue<T>(this EntityObject entityObject, string propertyName)
    {
        if (entityObject == null)
            return default(T);
        if (entityObject.EntityState == EntityState.Modified)
        {
            ObjectContext context = [YOUR OBJECT CONTEXT]
            ObjectStateEntry stateEntry = null;
            context.ObjectStateManager.TryGetObjectStateEntry(entityObject, out stateEntry);

            if (stateEntry != null)
                return (T)stateEntry.OriginalValues.GetValue(stateEntry.OriginalValues.GetOrdinal(propertyName));

        }

        // return the value of the property
        return (T)entityObject.GetType().GetProperty(propertyName).GetValue(entityObject, null);
    }

EntityCollection<T>

/// <summary>
   /// Extension methods for EntityCollection
   /// </summary>
   public static class EntityCollectionExtensions
   {
       /// <summary>
       /// Loads the entity collection if it hasn't already been loaded
       /// </summary>
       /// <typeparam name="T">Type of entity collection</typeparam>
       /// <param name="entityCollection">Entity collection to potentially load entities into</param>
       /// <param name="entitySource">The source entity which has the entity collection relationship (modified or unchanged only)</param>
       public static void EnsureLoaded<T>(this EntityCollection<T> entityCollection, EntityObject entitySource) where T : class, IEntityWithRelationships
       {
           if (entitySource != null && entityCollection != null && !entityCollection.IsLoaded )
           {
               if (entitySource.EntityState == System.Data.EntityState.Modified || entitySource.EntityState == System.Data.EntityState.Unchanged)
               {
                   entityCollection.Load();
               }
           }
       }

       /// <summary>
       /// Returns the collection as a queryable type
       /// </summary>
       /// <typeparam name="T">Type of entity collection</typeparam>
       /// <param name="entityCollection">Entity collection to return as a queryable object</param>
       /// <param name="ensureLoaded">Flag to determine if to load the collection if it has not been done so already</param>
       /// <returns>Queryable object for the in memory collection</returns>
       public static IQueryable<T> AsQueryable<T>(this EntityCollection<T> entityCollection, bool ensureLoaded, EntityObject entitySource) where T : class, IEntityWithRelationships
       {
           if (ensureLoaded)
               EnsureLoaded(entityCollection, entitySource);
           return entityCollection.AsQueryable();
       }

 

EntityReference<T>

 

/// <summary>
   /// Extension methods for EntityReference
   /// </summary>
   public static class EntityReferenceExtensions
   {

       /// <summary>
       /// Loads the entity reference or its value if it hasn't already been loaded.
       /// </summary>
       /// <typeparam name="T">Type of entity reference</typeparam>
       /// <param name="entitySource">The source entity which has the entity reference relationship (added, modified or unchanged only)</param>
       public static void EnsureLoaded<T>(this EntityReference<T> entityReference, EntityObject entitySource) where T : class, IEntityWithRelationships
       {
           if (entitySource != null && entityReference != null && !entityReference.IsLoaded && entityReference.EntityKey != null)
           {
               if (entitySource.EntityState == System.Data.EntityState.Added) // add the value directly as load will throw
               {
                   if (entityReference.Value == null)
                       entityReference.Value = LoadByKey<T>(entityReference.EntityKey);
               }
               else if (entitySource.EntityState == System.Data.EntityState.Modified || entitySource.EntityState == System.Data.EntityState.Unchanged)
               {
                   entityReference.Load();
               }
           }
       }

privateT LoadByKey<T>(object entityKey)
{
    if (entityKey == null)
        throw new ArgumentNullException("Supplied entity key is null, unable to load entity", "entityKey");
    // make sure the object is loaded in the object context
    ObjectContext objectContext = [YOUR OBJECT CONTEXT];
    EntityKey key = (EntityKey)entityKey;
    ObjectStateEntry entry;
    if (!objectContext.ObjectStateManager.TryGetObjectStateEntry(entityKey, out entry) || entry.Entity == null)
    {
        return (T)objectContext.GetObjectByKey(key);
    }
    return (T)entry.Entity;
}

       /// <summary>
       /// Whether or not the entity reference has an entity key with a value present
       /// </summary>
       public static bool HasEntityKeyFirstValue<T>(this EntityReference<T> entityReference) where T : class, IEntityWithRelationships
       {
           return entityReference != null && entityReference.EntityKey.HasFirstValue<int>();
       }

       /// <summary>
       /// Get entity key with a value present
       /// </summary>
       public static int GetEntityKeyFirstValue<T>(this EntityReference<T> entityReference) where T : class, IEntityWithRelationships
       {
           if (entityReference != null)
               return entityReference.EntityKey.GetFirstValue<int>();
           return 0;
       }

 

EntityKey

 

/// <summary>
   /// Extension methods for EntityKey
   /// </summary>
   public static class EntityKeyExtensions
   {

       /// <summary>
       /// Gets the first entity key value
       /// </summary>
       /// <returns>the first entity key value</returns>
       public static T GetFirstValue<T>(this EntityKey entityKey)
       {
           if (entityKey != null && entityKey.EntityKeyValues != null && entityKey.EntityKeyValues.Length > 0)
               return (T)entityKey.EntityKeyValues.First().Value;
           return default(T);
       }

       /// <summary>
       /// Sets the first entity key value
       /// </summary>
       public static void SetFirstValue<T>(this EntityKey entityKey, T value)
       {
           if (entityKey != null && entityKey.EntityKeyValues != null && entityKey.EntityKeyValues.Length > 0)
               entityKey.EntityKeyValues.First().Value = value;
           return;
       }

       /// <summary>
       /// Whether or not the entity key has a first value
       /// </summary>
       public static bool HasFirstValue<T>(this EntityKey entityKey)
       {
           var firstValue = GetFirstValue<T>(entityKey);
           var defaultValue = default(T);
           return (!firstValue.Equals(defaultValue));
       }

Saturday, August 16, 2008 3:26:05 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, July 04, 2008

Entity Framework Lazy Loading - A quick alternative with extension methods

I saw the following code on a customer object which made me think about affording a better way to query domain relationships without the extra methods, extension methods come to the rescue!

I realise transparent lazy loading a la Nhibernate is another option, but i think that this way keeps the spirit of explicitly loading from the database, but reduces the amount of code clutter on the client side so you are not forever checking whether a relationship is loaded or not, you simply request an IQueryable from the EntityCollection<T>.

        /// <summary>
        /// Finds a customer account with the specified ID
        /// </summary>
        /// <param name="customerAccountID">ID of the customer account to find</param>
        /// <returns>Customer account with the specified ID</returns>
        public CustomerAccount FindAccount(int customerAccountID)
        {
            if(!this.CustomerAccounts.IsLoaded)
            {
                this.CustomerAccounts.Load();
            }

            var query =
                from ca in this.CustomerAccounts
                where ca.CustomerAccountID == customerAccountID
                select ca;

            return query.FirstOrDefault();
        }

I added a static class with the extension methods for the EntityCollection type as follows:

public static class EntityCollectionExtensions
    {
        public static EntityCollection<T> EnsureLoaded<T>(this EntityCollection<T> entityCollection) where T : class, IEntityWithRelationships
        {
            if (!entityCollection.IsLoaded)
                entityCollection.Load();
            return entityCollection;
        }

        public static IQueryable<T> AsQueryable<T>(this EntityCollection<T> entityCollection, bool ensureLoaded) where T : class, IEntityWithRelationships
        {
            if (ensureLoaded)
                entityCollection = EnsureLoaded<T>(entityCollection);
            return entityCollection.AsQueryable();        }
    }

This allows you to do the following, which will only go to the database if the relationship is not loaded.

            var query =
                from ca in this.CustomerAccounts.AsQueryable(true) // ensure the relationship is loaded and return a queryable on it
                where ca.CustomerAccountID == customerAccountID
                select ca;
    return query.FirstOrDefault();

Friday, July 04, 2008 8:44:57 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, June 24, 2008

A vote of confidence for the Entity Framework

I saw a post from the alt.net community here saying the EF was crap basically....http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/

The core complaints raise some important issues, but i really don't think we need to go ballistic, and in some cases the concerns are just plain wrong. Time would be better spent finishing the Linq for NHibernate provider don't you think??

I've been working solidly with EF since the SP1 beta came out and can honestly say it's holding up very well across a large, enterprise data model structure, and alongside usage of a repository pattern and dependency injection to factor out most of the direct dependencies on the EF ObjectContext, we have a system that can move towards POCO over time with relatively little refactoring.

Here's some of my responses:

The design of the framework entities is that they are data only, causing issues in maintainability and making it difficult or impossible to implement business objects or more “real-world” objects. 
Wrong, you use partial classes to extend the generated aspects of the entities. This is explicitly encouraged and we use it a lot for core business rules and validation. There is nothing to stop you adding new non persistent properties or methods, or indeed new classes that are used alongside the entities.

The design of the framework entities is that they cannot be persistence ignorant, so things like unit testing become next to impossible because you cannot test the model without the database (for instance).
There are (admittedly difficult) ways to get close to POCO. Rather than tear your hair out, we used the repository pattern around the EF and avoid using the object context directly. You are then only dependent on EntityObject, EntityReference and EntityCollection on your entities. If you are sensible about it and don't work on object context, your refactoring when vnext comes along will be significantly reduced. This is a happy compromise for us and works well.

Lazy loading is not supported at all and requires a lot of extra code to make work.  This confuses me.  I thought I saw "lazy-loading" demoed internally but I might be mistaken.
KP > 'By design';) but honestly pretty easy to wire it up, not really a "lot of extra code". I have worked for years with NH too, and the time saved using the designer with EF more than makes up for it:)

Shared, canonical models contradict software best practices.  This appears to be related to using a single shared model for multiple contexts in the EF, rather than multiple models, one for each individual context. 
KP > Well, it may be a criticism of the vision of EF (the more than just an ORM story), but not of its core ORM functionality. Our clients are interested in the reporting aspects on their entity models without writing excessive code. It remained to be seen how this will pan out, but surely this is not a reason to pledge a vote of no confidence in a piece of technology?

Excessive merge conflicts with source control.  Apparently, since the diagram contains the model and the visualization, it causes tons of merge conflicts when a team is using it.
A somewhat moot point for most teams. We've settled on having a 'domain master', not a biggy for most teams? shared design on the database, entities and relationships would get messy in the best of worlds, i don't think this is a biggy.

Tuesday, June 24, 2008 5:22:28 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [6]  |  Trackback
 Thursday, May 29, 2008

Polymorphic Repository for ADO.Net Entity Framework

Wow, what a sexy title!

This post shows how you can have a repository pattern with the entity framework .

So, here we have a generic repository interface through which you can do all the nice things. You would normally use Castle Windsor (or similar Dependency Injection tool) to configure the Repository implementation (such as EFRepository) so you then just have a dependency on the interface, which is nice. Here's a snippet of how to configure the EFRepository to be used for all requests for IRepository from Castle Windsor. Note the ability to change object contexts and even the repository implementation, as long as IRepository is supported, the application won't care.

<castle>
    <components>

         <component id="objectContext" type="YourObjectContext"  ></component>
      <component id="iEFRepository" service="YourIRepository" type="YourEFRepository"
        <parameters>
          <objectContext>${objectContext}</objectContext>
        </parameters>
      </component>
    </components>
  </castle>

Note the reflection in the EFRepository implementation which allows you to query and work with all types in a hierarchy. By default you can't work directly with sub types in EF, you have to do extra work to get to them. The reflection gets the base type before communication with the ObjectContext to ensure minimal fussing about for the developer. Note i don't understand why this isn't built in to be honest, perhaps they ran out of time!

The whole point of this is that you avoid using your application's ObjectContext explicitly and only work with the core business entities that are then managed by the Entity Framework. This allows us to have a good separation of concerns between the various layers (although our entities are not pure POCO sadly). Note that i have only exposed the most widely used features of ObjectContext, you can extend your Repository interface and implementation to expose more advanced parts of the ObjectContext implementation if needs be.

In the future, EF may move towards greater persistence ignorance, but in the mean time structuring your application working off a Repository interface will mean minimal changes as EF changes moving forwards.

IRepository interface

public interface IRepository
  {

      /// <summary>
      /// Return reference to an underlying repository context
      /// </summary>
      /// <returns>the repository context</returns>
      object GetRepositoryContext();

      /// <summary>
      /// Return strongly typed IQueryable
      /// </summary>
      IQueryable<T> GetQuery<T>();

      /// <summary>
      /// Load entity from the repository or store if necessary
      /// </summary>
      /// <typeparam name="T">the entity type to load</typeparam>
      /// <param name="where">where condition</param>
      /// <returns>the loaded entity</returns>
      T Load<T>(Expression<Func<T, bool>> whereCondition);

      /// <summary>
      /// Mark entity to be deleted within the repository
      /// </summary>
      /// <param name="entity">The entity to delete</param>
      void Delete<T>(T entity);

      /// <summary>
      /// Add entity to the repository
      /// </summary>
      /// <param name="entity">the entity to add</param>
      /// <returns>The added entity</returns>
      void Add<T>(T entity);

      /// <summary>
      /// Updates entity within the the repository
      /// </summary>
      /// <param name="entity">the entity to update</param>
      /// <returns>The updates entity</returns>
      void Update<T>(T entity);

      /// <summary>
      /// Save all changes from repository to store
      /// </summary>
      /// <returns>Total number of objects affected</returns>
      int SaveChanges();

  }

Now we have our proper EFRepository.......

EFRepository implementation

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

public class EFRepository : IRepository, IDisposable
  {
      private ObjectContext _objectContext;

      private Type GetBaseType(Type type)
      {
          Type baseType = type.BaseType;
          if (baseType != null && baseType != typeof(EntityObject))
          {
              return GetBaseType(type.BaseType);
          }
          return type;
      }

      private bool HasBaseType(Type type, out Type baseType)
      {
          Type originalType = type.GetType();
          baseType = GetBaseType(type);
          return baseType != originalType;
      }

      public EFRepository(ObjectContext objectContext)
      {
          _objectContext = objectContext;
      }

      public ObjectContext ObjectContext
      {
          get
          {
              return _objectContext;
          }
      }

      public object GetRepositoryContext()
      {
          return this.ObjectContext;
      }

      public IQueryable<T> GetQuery<T>()
      {
          Type baseType;
          if (HasBaseType(typeof(T), out baseType))
          {
              return this.ObjectContext.CreateQuery<T>("[" + baseType.Name.ToString() + "]").OfType<T>();
          }
          else
          {
              return this.ObjectContext.CreateQuery<T>("[" + typeof(T).Name.ToString() + "]");
          }
      }

      public T Load<T>(Expression<Func<T, bool>> whereCondition)
      {
          return this.GetQuery<T>().Where(whereCondition).First();
      }

      public void Add<T>(T entity)
      {
          this.ObjectContext.AddObject(GetBaseType(typeof(T)).Name.ToString(), entity);      
      }

      public void Update<T>(T entity)
      {
          EntityObject entityObject = entity as EntityObject;
          ObjectContext objectContext = this.ObjectContext;
          objectContext.ApplyPropertyChanges(
              GetBaseType(typeof(T)).Name.ToString(),
              objectContext.GetObjectByKey(entityObject.EntityKey)
          );
      }

      public void Delete<T>(T entity)
      {
          this.ObjectContext.DeleteObject(entity);
      }

      public int SaveChanges()
      {
          return this.ObjectContext.SaveChanges();
      }

      public void Dispose()
      {
          if (_objectContext != null)
          {
              _objectContext.Dispose();
          }
      }

  }

Thursday, May 29, 2008 4:13:14 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, May 20, 2008

FriendFeed is cool

http://friendfeed.com/kpatton contains a list of all my online activity, essentially blog posts, youtube, flickr and twitter stuff. Nice idea, although there seems to be a new social networking site every 5 minutes and i'm struggling to keep up!

Tuesday, May 20, 2008 7:07:04 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, March 05, 2008

MOSS 2007 64 bit virtual development environment

Moss 2007 64 bit virtual development environment build documentation
Wednesday, March 05, 2008 3:56:41 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Thursday, February 28, 2008

Moss 2007 with SP1 together

Lots of people are obviously intending to install the office service pack 1 onto their Moss installations. However, what's the advice if you are (like me) creating a new multi-server moss farm and you want to ensure you rollout moss 2007 with SP1 applied?

Well, looking at the official documentation just didn't look like it was easily possible, and there was conflicting advice on the web around when to install SP1.

e.g. Configure your whole farm or just the SSP? Run the updates after the initial installation but don't run the config wizard? etc. etc.

This is until that is you realise that you can use the /Updates folder on the root of the Moss installation files, which is what the folder is for, to provision updates/patches.

So follow these five steps to Moss 2007 with SP1 install heaven:

1. Copy the contents of the MOSS 2007 CD to your hard drive (e.g. C:\MossWithSP1)

2. Download WSS 3.0 SP1 and Office 2007 SP1 (e.g C:\MossSp1)

3. Extract the contents to the Updates folder within your locally copied Moss installation by running the following at the command prompt: 

C:\MossSp1\Wssv3sp1-kb936988-x86-fullfile-en-us.exe /extract:c:\MossWithSP1
C:\MossSp1\Officeserver2007sp1-kb936984-x86-fullfile-en-us.exe /extract:c:\MossWithSP1

4. Use ImgBurn to burn the C:\MossWithSp1 back to an iso or to cd.

5. Use this disc on all future new Moss farms you build to avoid the need to upgrade to SP1

Now why on earth didn't Microsoft do this for new installations and make it available on MSDN!!??

Thursday, February 28, 2008 9:32:00 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, January 31, 2008

Moss 2007 Development Environment Setup - Update

DC with NAt mode best way to run a smoo 2007 development vm
Thursday, January 31, 2008 12:28:47 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, December 27, 2007

Managing and publishing media with Windows Live Photo Gallery

It's not often i gush about windows software, particularly considering how utterly vista has failed to capture the imagination of the ordinary user. Included with vista was the nice Windows Photo Gallery which was really an IPhoto equivalent built into the OS.

Now, Windows Live Photo Gallery (wikipedia: http://en.wikipedia.org/wiki/Windows_Live_Photo_Gallery, download: http://get.live.com/photogallery/overview) is available for XP and Vista users which is essentially an upgrade to this vista application with some lovely new features that i think should make it an essential download for any blogger or user who publishes images and videos to the web on a regular basis.

First off, the name, Windows Live Media Gallery anyone?

I think MS made a mistake in calling the application Windows Live Photo Gallery, instead it should be Windows Live Media Gallery because it handles the tagging, previewing, burning, playing and publishing of video content just as gracefully as photo media. I suspect this was to avoid confusion with the Windows Media Player application. Perhaps the whole interface should be merged who knows...

Importing Media

When you import photos and videos into Windows Live Photo Gallery you get very granular control over where the files go and crucially the auto-tagging of the files. In the base version of Windows Photo Gallery on vista, you could only tag in an all or nothing way for all imported files. So, getting stuff in and organising your import is a breeze.

Tagging and Publishing Media

Creating, organising and assigning media to tags is easy, with drag and drop support throughout. Best of all, tags are retained when publishing media. A new Publish menu item appears at the top of the main interface, allowing you to publish images to MSN Spaces AND Flickr. I highly recommend Flickr and it's great to see MS support a 3rd party service out of the box like this. Tagging is preserved when publishing to Flickr and Flickr has officially announced support for Windows Live Photo Gallery.

Unfortunately, the only thing that lets down the Publish option is that for video only MSN Video is supported, although i hope YouTube support will be forthcoming perhaps in a future release. MSN Video is fine and dandy and free, but i have all my videos at YouTube and really want to publish there with full tagging integration a la Flickr support. In the meantime, i simply utilise the YouTube multi file upload interface and manually re-assign tags not a biggy as i don't have as many videos as photos.

Windows Live Writer

Whatever blog you use, you should really use Windows Live Writer as an excellent editor for publishing to your blog. It will work with almos any blog out there and is easy to set up as long as you have your blog's home page url, username and password. I find it much nicer to write up blog posts rather than having to login to my blog website each time.

It is also a highly extensible little applicaiton and already has plugins such as a Flickr Plugin to support selecting one or more images from your Flickr stream.

You can also easily insert videos you have posted to YouTube, Google Video or MSN Video.

There is a site, Windows Live Writer plugins, where you can view even more useful plugins for this essential blogging tool.

Thursday, December 27, 2007 10:26:54 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, December 24, 2007

Alt TV Interactive Txt

Congrats to Andy, Teresa, Chris et al at Hyro NZ for getting this up and running. Despite many obstacles this is now a New Zealand first which i've been helping Andy get up and running for months. I think this'll take off once the other channels eye ball it and i wish the team all the very best of luck with this over the coming months.

Check it out on Sky Channel 65, txts only $0.99 each!

23122007057

Monday, December 24, 2007 12:00:47 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, December 22, 2007

Twitter stream now in operation

twitter.
Saturday, December 22, 2007 8:44:47 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, December 17, 2007

Fring is the Future

fringing awesome
Monday, December 17, 2007 12:22:37 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, December 11, 2007

Nokia N95

new mobile phone/camera/video thingy
Tuesday, December 11, 2007 3:12:34 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, October 31, 2007

AVJennings Website Goes Live

We've been working on this one for a while, finally goes live, http://www.avjennings.com.au. Built using www.kentico.com our favourite CMS.

Wednesday, October 31, 2007 9:02:03 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 13, 2007

Garmin Forerunner 305

Woohoo! My GPS wristwatch thingy has arrived. It measures distance, speed, elevation, heart rate, calorie count as you run. Even allows you to race against your previous runs and export the runs to google maps!

cf-lg

https://buy.garmin.com/shop/shop.do?pID=349 

Thursday, September 13, 2007 11:23:21 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Monday, August 20, 2007

Moving Offices

movin on up
Monday, August 20, 2007 8:29:18 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Saturday, August 11, 2007

MOSS 2007 Demonstration Machine Setup

MOSS 2007 Demonstration Machine Setup
Saturday, August 11, 2007 11:32:10 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, July 23, 2007
 Monday, July 16, 2007

Technorati Profile

Hi, Pointless little post to ensure my technorati profile gets set up ok.

 

 

Technorati Profile
Monday, July 16, 2007 7:52:52 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, July 13, 2007

MOSS 2007 Development Environment - Virtual Server Set Up

Take a deep breath, the complete guide to setting up a MOSS 2007 Development Virtual Machine
Friday, July 13, 2007 9:18:59 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, June 29, 2007

MOSS 2007 Development - Virtual Server Set Up

MOSS 2007 Development Virtual Server Set Up
Friday, June 29, 2007 1:19:48 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, June 04, 2007

Geni Rocks

I just had to blog about a really great website i just found for building family trees called www.geni.com. It really is one of the most easy to use websites i've ever seen, have a try. It also doubles as a handy birthday reminder tool and you can store family photos etc.

Monday, June 04, 2007 8:36:12 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Friday, June 01, 2007

Steve and Bill Chinwag

Steve Jobs and Bill Gates in a very, very rare interview together.

http://d5.allthingsd.com/20070530/steve-jobs-and-bill-gates-together-part-1-of-7/

Friday, June 01, 2007 11:38:13 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, May 31, 2007

It's all about perception

working in software is so much fun;)

Thursday, May 31, 2007 10:06:32 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, May 13, 2007

Quero to the rescue!

I posted previously about the truly awful UI experience in IE7, particularly the fact that it is not customisable.

Well, glory be the wonderful free add on Quero makes IE 7 worth using again as it groups all the navigation options (back, forwards, refresh, stop and home) where they should be, next to each other!

There are also some other nifty features such as search highlighting, themes and the ability to put the main menu navigation back where it shoudl be, at the top of the window!

Sunday, May 13, 2007 9:26:00 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, March 14, 2007

Vista Ultimate DreamScene

I just downloaded the latest updates for windows vista to find some lovely little videos you can setup as the background for your desktop environment.

DreamScene on my PC (2.5MB, MPG)
Wednesday, March 14, 2007 7:51:18 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, February 26, 2007

Firefox 2 Usability Trumps IE7

Now, let me state up front i am no LAMP or Firefox bigot. For better or worse i am an MS fan, already having converted my household to Vista and OneCare. However...having used IE7 since the early betas i'm afraid to say that Firefox is by far the most usable, quicker browser. Although my evidence is anecdotal (i work and consult with many other developers,project managers, business analysts who all for the most part corroborate my theory), IE 7 is confusing on a very basic level..

OK, i have a widescreen, so these screenshots look worse than on a normal monitor. But hey, wasn't Vista developed with widescreen in mind (sidebar gadgetry etc.)? Anyway, i've marked the key web navigation elements in red below. Note how in IE 7 the back and forward buttons are standalone, but if you want to Stop or Refresh the page you have to go to the right of the address bar. And if you want to go home, you have to go underneath to the tab level, mmm.

I won't even mention the fact that MS broke all previous design and decided to hide the menu navigation. OK, you can show it, but then it doesn't appear where you would expect it at the top, but strangely nestled between the address bar level and the tab level. It just looks well, awkward...

All this would be almost forgivable if like most MS applications you could tinker with the menus, but lo and behold for some strange reason you can't do diddly except hide and show things, the position of everything is fixed, damn!

IE7

 

Contrast this with Firefox, which places all the key navigation elements right next to each other, and logicall places the menu bar at the top were it belongs. You can drag stuff about levels and the whole experience (particularly on a widescreen) is so much more pleasant.

Firefox

Monday, February 26, 2007 10:40:08 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, January 10, 2007

sky website - hunt the phone number

sky phone impossible
Wednesday, January 10, 2007 2:25:24 PM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [4]  |  Trackback
 Monday, January 08, 2007

spore - the best game ever?

new exciting game coming up
Monday, January 08, 2007 8:27:33 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, December 22, 2006

Annabel goes digital with the Nikon D200

new camera for annabel
Friday, December 22, 2006 9:13:56 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Telecom Broadband Loss of Synchronization Errors - Netgear DG834G solution

solution for broadband connection dropouts with telecom on netgear DG834G router.
Friday, December 22, 2006 9:00:34 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, December 08, 2006

new wii

wee wii
Friday, December 08, 2006 10:08:46 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Monday, October 30, 2006

My New PC 2006

good job i'm not into cars
Monday, October 30, 2006 1:13:20 AM (New Zealand Daylight Time, UTC+13:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, June 21, 2006

we are the champions

champions
Wednesday, June 21, 2006 5:51:18 PM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, June 02, 2006

user control libraries - interesting use of generics and proxy user controls with asp.net 2.0

user control libraries in asp.net 2.0
Friday, June 02, 2006 10:26:51 AM (New Zealand Standard Time, UTC+12:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Saturday, April 22, 2006