Regarding your second option, "Refresh on expiry", this doesn't work because CacheManager doesn't return the cached value if the item expired. And, while you "refresh" the cache, you'd eventually get a lot of cache misses from other callers. 
My suggestions:
If you have only a small amount of keys cached for 60 minutes and they all "work the same", just spin up a background task which runs async to your process and refreshes the cache every 15 minutes.
If you have many keys which can vary a lot in terms of expiration, you could cache the data with 60 minutes expiration and store a secondary key (a fake key with no actual value) with a 15 minutes expiration. Then, if the fake key expires, refresh the actual key/value... 
As key for the fake one, use a prefix+actual key for example and then listen to OnRemove event for example.
Quick example program
internal class Program
{
    private static ICacheManager<object> _cache;
    private static void Main(string[] args)
    {
        _cache = CacheFactory.Build(c => c.WithDictionaryHandle());
        _cache.OnRemoveByHandle += Cache_OnRemoveByHandle;
        for (var i = 0; i < 10; i++)
        {
            _cache.Add("key" + i, "data" + i);
            AddFakeKey("key" + i);
            Thread.Sleep(1000);
        }
        Console.ReadKey();
    }
    private static void AddFakeKey(string forKey)
    {
        _cache.Add(new CacheItem<object>("trigger_" + forKey, "n/a", ExpirationMode.Absolute, TimeSpan.FromSeconds(1)));
    }
    private static void Cache_OnRemoveByHandle(object sender, CacheItemRemovedEventArgs e)
    {
        // Remark: you might get this event triggered for each level of the cache e.Level can be checked to react only on the lowest level...
        Console.WriteLine("OnRemoveByHandle " + e.ToString());
        if (e.Key.StartsWith("trigger_") && e.Reason == CacheItemRemovedReason.Expired)
        {
            var key = e.Key.Substring(8);
            Console.WriteLine("Updating key " + key);
            // updating the key
            _cache.Update(key, _ => "new value");
            // add a new fake key for another round
            AddFakeKey(key);
        }
    }
}
This even works with Redis if keyspace notifications are enabled.