I like creating my own static wrapper class for the System.Web.Caching.Cache class.
Essentially you create a class in your web application module, and create all the standard Cache functions (get, add, remove, etc). The methods need to be implemented with generics to ensure type safety.
Here is a good example
You then create another static class, which acts as like a service model from your web tier through to your data tier.
Your web tier would invoke methods on the static class, which would first generate a CacheKey based on the supplied method parameters, check cache, if found return, otherwise call data layer, add to cache and return.
Depending on how your business objects are setup, your might need to provide deep copies (ie implement IClonable and ovveride the Clone method) on your objects.
Also, your cache solution depends on your web farm architecture. If you have lots of web servers, the chances are your data could become stale so you need to decide on the best option there (SQLCacheDependecy, Distributed Caching, etc).